# Water Calculator

Water Calculator Service is used to create meter readings, search meter readings, update existing meter readings, calculate water charges, generate demand, notify ULB officials using SMS & email on-demand generation and estimation of water charges (one-time cost) which involves costs like road-cutting charge, form fee, scrutiny fee, etc.

## Pre-requisites <a href="#pre-requisites" id="pre-requisites"></a>

Before you proceed with the documentation, make sure the following pre-requisites are met -

1. *Java 8*
2. The Kafka server is up and running
3. egov-persister service is running and has the water service persister configs path added to it
4. PSQL server is running and a database is created to store water connection/application data
5. The following services should be up and running:
   * egov-persister
   * egov-mdms
   * ws-services
   * billing-service

## Key Functionalities <a href="#key-functionalities" id="key-functionalities"></a>

* Calculate water charges and taxes based on the billing slab
* Calculate meter reading charge for water connection
* Generate demand
* Scheduler for generating the demand (for non-metered connection)

<table><thead><tr><th width="288">Environment variables</th><th>Description</th></tr></thead><tbody><tr><td><code>notification.sms.enabled</code></td><td>This variable is to check the SMS notifications are enabled or not.</td></tr><tr><td><code>notification.email.enabled</code></td><td>This variable is to check the email notifications are enabled or not.</td></tr><tr><td><code>download.bill.link.path</code></td><td>This variable is for download bill reciept path</td></tr><tr><td><code>egov.demand.gp.user.link</code></td><td>This variable is to get the common link to the home page</td></tr></tbody></table>

## Deployment Details <a href="#deployment-details" id="deployment-details"></a>

1. Deploy the latest version of ws-service and ws-calculator
2. Add the `water-persist.yml` and `water-meter.yml` files to the config folder in git. Update the environment YAML file by adding a parameter called `persist-yml-path` with the path to these files.

## Configuration Details <a href="#configuration-details" id="configuration-details"></a>

### MDMS Configuration <a href="#mdms-configuration" id="mdms-configuration"></a>

**Master Config:**

```
"ws-services-calculation": {
    
    "WCBillingSlab": {
      "masterName": "WCBillingSlab",
      "isStateLevel": true,
      "uniqueKeys": []
    },
   
    "CalculationAttribute": {
      "masterName": "CalculationAttribute",
      "isStateLevel": true,
      "uniqueKeys": []
    }
  }
```

**Billing Slabs:**

Criteria -&#x20;

1. connection type
2. building type
3. calculation attribute
4. property usage type

The above combination is used to define the billing slab. Billing Slab is defined in MDMS under the ws-services-calculation folder with the [WCBillingSlab](https://github.com/egovernments/mdms-mgramseva/blob/DEV/data/pb/ws-services-calculation/WCBillingSlab.json). Find below a sample slab.

```
  {
      "id": "1",
      "buildingType": "RESIDENTIAL",
      "connectionType": "Metered",
      "calculationAttribute": "Water consumption",
      "minimumCharge": 100,
      
      "slabs": [
        {
          "from": 0,
          "to": 10,
          "charge": 2,
          "meterCharge": 50
        },
        {
          "from": 10,
          "to": 20,
          "charge": 2.5,
          "meterCharge": 50
        },
        {
          "from": 20,
          "to": 30,
          "charge": 8,
          "meterCharge": 150
        },
        {
          "from": 30,
          "to": 40,
          "charge": 12,
          "meterCharge": 150
        },
        {
          "from": 40,
          "to": 1000000000,
          "charge": 15,
          "meterCharge": 150
        }
      ]
    },
    {
      "id": "5",
      "buildingType": "RESIDENTIAL",
      "calculationAttribute": "No. of taps",
      "connectionType": "Non Metered",
      
      "minimumCharge": 100,
      "slabs": [
        {
          "from": 0,
          "to": 1000000000,
          "charge": 100
        }
      ]
    },
```

The calculation applies the specified slab based on the water connection criteria.

**Estimation:**

**Water charge and tax**

The water charge is based on the billing slab, and the water application charge will be based on the slab and tax based on the master configuration.&#x20;

```
{
  "tenantId": "pb.massewal",
  "moduleName": "ws-services-calculation",
  "WCBillingSlab": [
    {
      "id": "1",
      "buildingType": "RESIDENTIAL",
      "connectionType": "Metered",
      "calculationAttribute": "Water consumption",
      "minimumCharge": 100,
      
      "slabs": [
        {
          "from": 0,
          "to": 1000000,
          "charge": 2,
          "meterCharge": 50
        }
      ]
    },
    {
      "id": 2,
      "buildingType": "COMMERCIAL",
      "calculationAttribute": "Water consumption",
      "connectionType": "Metered",
      
      "minimumCharge": 200,
      "slabs": [
        {
          "from": 0,
          "to": 1000000,
          "charge": 13.31,
          "meterCharge": 532.4
          
        }
      ]
    },
    {
      "id": 3,
      "buildingType": "MIXED",
      "calculationAttribute": "Water consumption",
      "connectionType": "Metered",
      
      "minimumCharge": 200,
      "slabs": [
        {
          "from": 0,
          "to": 1000000,
          "charge": 13.31,
          "meterCharge": 532.4
          
        }
      ]
    },
    {
      "id": "4",
      "buildingType": "PUBLICSECTOR",
      "calculationAttribute": "Water consumption",
      "connectionType": "Metered",
      "minimumCharge": 150,
      
      "slabs": [
        {
          "from": 0,
          "to": 1000000,
          "charge": 8,
          "meterCharge": 250
        }
      ]
    },
    {
      "id": "5",
      "buildingType": "RESIDENTIAL",
      "calculationAttribute": "Flat",
      "connectionType": "Non_Metered",
      
      "minimumCharge": 150
    },
    {
      "id": "6",
      "buildingType": "COMMERCIAL",
      "calculationAttribute": "Flat",
      "connectionType": "Non_Metered",
      
      "minimumCharge": 150
    },
    {
      "id": "7",
      "buildingType": "MIXED",
      "calculationAttribute": "Flat",
      "connectionType": "Non_Metered",
      
      "minimumCharge": 150
    },
       {
      "id": "8",
      "buildingType": "PUBLICSECTOR",
      "calculationAttribute": "Flat",
      "connectionType": "Non_Metered",
      
      "minimumCharge": 150
    }
  ]
}
```

### Actions & Role Action Mapping <a href="#actions-and-role-action-mapping" id="actions-and-role-action-mapping"></a>

#### **Actions**

```
[
  {
      "id": {{PLACEHOLDER1}},
      "name": "Bulk Demand Generation",
      "url": "/ws-calculator/waterCalculator/_bulkDemand",
      "parentModule": "",
      "displayName":"Bulk Demand Generation",
      "orderNumber": 1,
      "enabled": false,
      "serviceCode": "ws-services",
      "code": "null",
      "path": ""
    },
    {
      "id": {{PLACEHOLDER2}},
      "name": "Demand Calculation",
      "url": "/ws-calculator/waterCalculator/_calculate",
      "parentModule": "",
      "displayName": "Demand Calculation",
      "orderNumber": 2,
      "enabled": false,
      "serviceCode": "ws-services",
      "code": "null",
      "path": ""
    },
    {
      "id": {{PLACEHOLDER3}},
      "name": "Meter Demand Calculation",
      "url": "/ws-calculator/meterConnection/_create",
      "parentModule": "",
      "displayName": "Meter Demand Calculation",
      "orderNumber": 3,
      "enabled": false,
      "serviceCode": "ws-services",
      "code": "null",
      "path": ""
    },
    {
      "id": {{PLACEHOLDER4}},
      "name": "Meter Demand search",
      "url": "/ws-calculator/meterConnection/_search",
      "parentModule": "",
      "displayName": "Meter Demand search",
      "orderNumber": 3,
      "enabled": false,
      "serviceCode": "ws-services",
      "code": "null",
      "path": ""
    },
    {
      "id": {{PLACEHOLDER5}},
      "name": "Demand Estimate",
      "url": "/ws-calculator/waterCalculator/_estimate",
      "parentModule": "",
      "displayName": "Demand Estimate",
      "orderNumber": 2,
      "enabled": false,
      "serviceCode": "ws-services",
      "code": "null",
      "path": ""
    }
]
```

#### **Role Action Mapping**

```
[
    {
      "rolecode": "BULK_DEMAND_PROCESSING",
      "actionid": {{PLACEHOLDER1}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "BULK_DEMAND_PROCESSING",
      "actionid": {{PLACEHOLDER2}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "BULK_DEMAND_PROCESSING",
      "actionid": {{PLACEHOLDER3}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "BULK_DEMAND_PROCESSING",
      "actionid": {{PLACEHOLDER4}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "COLLECTION_OPERATOR",
      "actionid": {{PLACEHOLDER4}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "GP_ADMIN",
      "actionid": {{PLACEHOLDER4}},
      "actioncode": "",
      "tenantId": "pb"
    },
    {
      "rolecode": "GP_ADMIN",
      "actionid": {{PLACEHOLDER5}},
      "actioncode": "",
      "tenantId": "pb"
    }
]
```

### **A**dd New BillingSlab/RateMaster <a href="#how-to-add-new-billingslab-ratemaster" id="how-to-add-new-billingslab-ratemaster"></a>

The charge for the given connection for a given billing cycle will be defined/identified by the system with the help of the **CalculationAtrribute** MDMS and **WCBillngSlab** MDMS.

CalcualtionAttribute helps to identify the type of calculation for the given ConnectionType below MDMS of

1. Metered Connection **water consumption** is the attribute used for the calculation of charge for the billing cycle i.e Based on the units consumed for a given billing cycle for a given connection would identify the actual charge from the **WCBIllingSlab** MDMS based on the **propertyType, calcautionAttribute** derived for a connection **and ConnectionType.**
2. Non-Metered Connection **Flat** is the attribute used for the calculation of the charge for a given billing cycle, i.e. for a Non-Metered connection, there would be a flat charge for the given billing cycle. The amount can be derived from the **WCBillingSlab** MDMS based on the **propertyType, calcautionAttribute** derived for a connection **and ConnectionType.**

### Demand Generation <a href="#demand-generation" id="demand-generation"></a>

Once water is sent to the calculator, its tax estimates are calculated. Using these tax head estimates, demand details are created. For every tax head, the estimated demand generates a corresponding demand detail.

When the `_calculate` API is called, demand is first searched based on the connection number or application number and the demand period. If demand already exists, it is updated with the new information. Otherwise, a new demand is generated for the financial year period.

During an update, if the tax head estimates change, the difference in amount for that tax head is added as a new demand detail. For example, if the initial demand has one demand detail with WATER\_CHARGE equal to 120.

```
"demandDetails": [
                {
                    "id": "77ba1e93-a535-409c-b9d1-a312c409bd45",
                    "demandId": "687c3176-305b-461d-9cec-2fa26a30c88f",
                    "taxHeadMasterCode": "WATER_CHARGE",
                    "taxAmount": 120,
                    "collectionAmount": 120,
                    "additionalDetails": null,
                    "auditDetails": {
                        "createdBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "lastModifiedBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "createdTime": 1583675275873,
                        "lastModifiedTime": 1583675298705
                    },
                    "tenantId": "pb.amritsar"
                }
            ],
```

After updating if the WATER\_CHARGE increases to 150 we add one more demand detail to account for the increased amount. The demand detail will be updated to:

```
"demandDetails": [
                {
                    "id": "77ba1e93-a535-409c-b9d1-a312c409bd45",
                    "demandId": "687c3176-305b-461d-9cec-2fa26a30c88f",
                    "taxHeadMasterCode": "WATER_CHARGE",
                    "taxAmount": 120,
                    "collectionAmount": 0,
                    "additionalDetails": null,
                    "auditDetails": {
                        "createdBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "lastModifiedBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "createdTime": 1583675275873,
                        "lastModifiedTime": 1583675298705
                    },
                    "tenantId": "pb.amritsar"
                },
                {
                    "id": "0d83f4b0-6442-11ea-bc55-0242ac130003 ",
                    "demandId": "687c3176-305b-461d-9cec-2fa26a30c88f",
                    "taxHeadMasterCode": "WATER_CHARGE",
                    "taxAmount": 30,
                    "collectionAmount": 0,
                    "additionalDetails": null,
                    "auditDetails": {
                        "createdBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "lastModifiedBy": "04956309-87cd-4526-b4e6-48123abd4f3d",
                        "createdTime": 1583675275873,
                        "lastModifiedTime": 1583675298705
                    },
                    "tenantId": "pb.amritsar"
                }
            ],
```

Round-off in the bill is based on the total amount, ensuring that the payable amount is a whole number. Each WS\_ROUNDOFF in the demand detail can be greater than 0.5, but the sum of all WS\_ROUNDOFF values is always less than 0.5.

### Demand Generation Scheduler (For Non-metered Connection) <a href="#demand-generation-scheduler-for-non-metered-connection" id="demand-generation-scheduler-for-non-metered-connection"></a>

**Description**

To generate demand for non-metered connections, we have a feature for batch demand generation. The scheduler is responsible for generating demand based on the tenant.

* The scheduler can be triggered using the scheduler API, scheduled as a cron job, or configured in Kubectl to hit the scheduler based on the configuration.
* After the scheduler is triggered, we can search for the list of tenants (cities) in the database.
* After obtaining the list of tenants, iterate through the list and generate the demand for specific tenants.
* Load the consumer codes for the tenant and push the calculation criteria to Kafka. The calculation criteria contain minimal information, including the consumer code and one boolean variable.
* After pushing the data into Kafka, the system consumes the records based on the batch configuration. For example, if the batch configuration is set to 50, the system will consume 50 calculation criteria at a time.
* After consuming the records (calculation criteria), the system processes the batch to generate the demand. If the batch processing is successful, the processed consumer codes are logged.
* If some records fail in the batch, the system pushes the batch into the dead letter batch topic. From there, the batch is processed one record at a time.
* If the record is successful, the system logs the consumer code. If the record fails, the data is pushed into a dead-letter single topic.
* Dead letter single topic contains information about failure records in Kafka.

#### **Use cases**

**If the same job triggers multiple times what will happen?**

If the same job triggers multiple times the system processes it again as mentioned above but at the demand level, it checks the demand based on consumer code and billing period. In case the demand already exists then it updates the demand or else creates the demand.

**Are we maintaining success or failure status anywhere?**

Currently, we are maintaining the status of failed records in Kafka.

#### **Configuration**

We need to configure the batch size for Kafka consumers. This configuration determines how much data is processed at a time.

```
ws.demand.based.batch.size=10
```

## Integration Details <a href="#integration-details" id="integration-details"></a>

### Integration Scope <a href="#integration-scope" id="integration-scope"></a>

The ws-calculator is integrated with ws-service. ws-services internally invoke the ws-calculator service to calculate and generate demand for the charges.

### Integration Benefits <a href="#integration-benefits" id="integration-benefits"></a>

WS calculator application is used to calculate the water application one-time fees and meter reading charges based on the different billing slabs. That's why the calculation and demand generation logic is separated from the WS service. So in future, if calculation logic requires modification the changes can be carried out for each implementation without modifying the WS service.

### Integration Steps <a href="#integration-steps" id="integration-steps"></a>

1. Once the water connection is activated for the metered connection, the employee can add meter reading details using the API - /ws-calculator/meterConnection/\_create. This generates the demand. The scheduler APIs should be called periodically for non-metered connections to generate the demand.
2. For the metered connection service, the /meterConnection/\_search API is used to get the previous meter reading,
3. To generate the demand for metered or non-metered water connection /waterCalculator/\_calculate API is used.
4. Users can pay partial/full/advance amounts for the metered or non-metered connection bill. The billing service would call back /waterCalculator/\_updateDemandAPI to update the demand-generated details in such cases.
5. /waterCalculator/\_jobscheduler API is used to generate demand for non-metered connections. This API can be called periodically.

## Reference Docs <a href="#reference-docs" id="reference-docs"></a>

<table><thead><tr><th width="262">Docs</th><th>APIs</th></tr></thead><tbody><tr><td><a href="https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/municipal-services/docs/water-sewerage-services.yaml#!/">API Swagger Contract</a></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/ws-calculator/meterConnection/_create</a></td></tr><tr><td><a href="/pages/FRZD8mI4HZgf65AUOmye">Water Service Document</a></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/ws-calculator/meterConnection/_search</a></td></tr><tr><td></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/waterCalculator/_estimate</a></td></tr><tr><td></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/waterCalculator/_calculate</a></td></tr><tr><td></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/waterCalculator/_updateDemand</a></td></tr><tr><td></td><td><a href="https://www.getpostman.com/collections/7ca1fb4384cf83c40c9d">/waterCalculator/_jobscheduler</a></td></tr></tbody></table>

*(Note: All the APIs are in the same Postman collection therefore the same link is added in each row).*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.digit.org/naljalseva/setup-naljalseva/configure-naljalseva/configure-backend-services/water-calculator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
