biller-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- biller_cli/__init__.py +0 -0
- biller_cli/ai/__init__.py +397 -0
- biller_cli/ai/ingest.py +394 -0
- biller_cli/commands/down.py +96 -0
- biller_cli/commands/downgrade.py +142 -0
- biller_cli/commands/init.py +210 -0
- biller_cli/commands/up.py +138 -0
- biller_cli/commands/upgrade.py +271 -0
- biller_cli/main.py +34 -0
- biller_cli/templates/biller-user-layer/pom.xml +100 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/ApplicationContext.java +13 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/config/DatabaseConfig.java +35 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/config/WebCorsConfig.java +21 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/controller/BbpsRequestController.java +98 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/dao/impl/BillFetchDaoImpl.java +135 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/dao/impl/BillPaymentDaoImpl.java +100 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/provider/BillingProviderConfig.java +34 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/provider/BillingProviderProperties.java +92 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/provider/impl/CsvBillingProvider.java +257 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/provider/impl/ExcelBillingProvider.java +261 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/provider/impl/PostgresBillingProvider.java +210 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/service/impl/BillFetchServiceImpl.java +131 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/service/impl/BillPaymentServiceImpl.java +175 -0
- biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/service/impl/HeartbeatServiceImpl.java +136 -0
- biller_cli/templates/biller-user-layer/src/main/resources/application.properties +88 -0
- biller_cli/templates/pom.xml +33 -0
- biller_cli/utils/preflight.py +151 -0
- biller_cli/utils/secrets.py +37 -0
- biller_cli/utils/version_pin.py +67 -0
- biller_cli-0.1.0.dist-info/METADATA +17 -0
- biller_cli-0.1.0.dist-info/RECORD +33 -0
- biller_cli-0.1.0.dist-info/WHEEL +4 -0
- biller_cli-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
4
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
5
|
+
<modelVersion>4.0.0</modelVersion>
|
|
6
|
+
<parent>
|
|
7
|
+
<groupId>com.bharatconnect.biller</groupId>
|
|
8
|
+
<artifactId>test-biller-integrator</artifactId>
|
|
9
|
+
<version>1.0.0</version>
|
|
10
|
+
</parent>
|
|
11
|
+
<artifactId>biller-user-layer</artifactId>
|
|
12
|
+
<version>1.0.0</version>
|
|
13
|
+
<packaging>jar</packaging>
|
|
14
|
+
<description>BBPS Biller User Layer</description>
|
|
15
|
+
<properties>
|
|
16
|
+
<biller.core.version>{{BILLER_CORE_VERSION}}</biller.core.version>
|
|
17
|
+
</properties>
|
|
18
|
+
<dependencies>
|
|
19
|
+
<dependency>
|
|
20
|
+
<groupId>com.bharatconnect.biller</groupId>
|
|
21
|
+
<artifactId>biller-core</artifactId>
|
|
22
|
+
<version>${biller.core.version}</version>
|
|
23
|
+
</dependency>
|
|
24
|
+
<dependency>
|
|
25
|
+
<groupId>org.springframework.boot</groupId>
|
|
26
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
27
|
+
</dependency>
|
|
28
|
+
<dependency>
|
|
29
|
+
<groupId>org.springframework.boot</groupId>
|
|
30
|
+
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
31
|
+
</dependency>
|
|
32
|
+
<dependency>
|
|
33
|
+
<groupId>org.springframework.boot</groupId>
|
|
34
|
+
<artifactId>spring-boot-starter-jdbc</artifactId>
|
|
35
|
+
</dependency>
|
|
36
|
+
<dependency>
|
|
37
|
+
<groupId>org.postgresql</groupId>
|
|
38
|
+
<artifactId>postgresql</artifactId>
|
|
39
|
+
<scope>runtime</scope>
|
|
40
|
+
</dependency>
|
|
41
|
+
<dependency>
|
|
42
|
+
<groupId>org.apache.poi</groupId>
|
|
43
|
+
<artifactId>poi-ooxml</artifactId>
|
|
44
|
+
<version>5.2.5</version>
|
|
45
|
+
</dependency>
|
|
46
|
+
<dependency>
|
|
47
|
+
<groupId>org.apache.commons</groupId>
|
|
48
|
+
<artifactId>commons-lang3</artifactId>
|
|
49
|
+
</dependency>
|
|
50
|
+
<dependency>
|
|
51
|
+
<groupId>jakarta.xml.bind</groupId>
|
|
52
|
+
<artifactId>jakarta.xml.bind-api</artifactId>
|
|
53
|
+
</dependency>
|
|
54
|
+
<dependency>
|
|
55
|
+
<groupId>com.sun.xml.bind</groupId>
|
|
56
|
+
<artifactId>jaxb-impl</artifactId>
|
|
57
|
+
<version>4.0.4</version>
|
|
58
|
+
</dependency>
|
|
59
|
+
<dependency>
|
|
60
|
+
<groupId>org.projectlombok</groupId>
|
|
61
|
+
<artifactId>lombok</artifactId>
|
|
62
|
+
<optional>true</optional>
|
|
63
|
+
</dependency>
|
|
64
|
+
<dependency>
|
|
65
|
+
<groupId>org.springframework.boot</groupId>
|
|
66
|
+
<artifactId>spring-boot-starter-test</artifactId>
|
|
67
|
+
<scope>test</scope>
|
|
68
|
+
</dependency>
|
|
69
|
+
</dependencies>
|
|
70
|
+
<build>
|
|
71
|
+
<plugins>
|
|
72
|
+
<plugin>
|
|
73
|
+
<groupId>org.apache.maven.plugins</groupId>
|
|
74
|
+
<artifactId>maven-compiler-plugin</artifactId>
|
|
75
|
+
<configuration>
|
|
76
|
+
<source>17</source>
|
|
77
|
+
<target>17</target>
|
|
78
|
+
<annotationProcessorPaths>
|
|
79
|
+
<path>
|
|
80
|
+
<groupId>org.projectlombok</groupId>
|
|
81
|
+
<artifactId>lombok</artifactId>
|
|
82
|
+
<version>1.18.32</version>
|
|
83
|
+
</path>
|
|
84
|
+
</annotationProcessorPaths>
|
|
85
|
+
</configuration>
|
|
86
|
+
</plugin>
|
|
87
|
+
<plugin>
|
|
88
|
+
<groupId>org.springframework.boot</groupId>
|
|
89
|
+
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
90
|
+
<executions>
|
|
91
|
+
<execution>
|
|
92
|
+
<goals>
|
|
93
|
+
<goal>repackage</goal>
|
|
94
|
+
</goals>
|
|
95
|
+
</execution>
|
|
96
|
+
</executions>
|
|
97
|
+
</plugin>
|
|
98
|
+
</plugins>
|
|
99
|
+
</build>
|
|
100
|
+
</project>
|
biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/ApplicationContext.java
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package bharat.connect.biller;
|
|
2
|
+
|
|
3
|
+
import org.springframework.boot.SpringApplication;
|
|
4
|
+
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
5
|
+
import org.springframework.scheduling.annotation.EnableAsync;
|
|
6
|
+
|
|
7
|
+
@EnableAsync
|
|
8
|
+
@SpringBootApplication(scanBasePackages = "bharat.connect.biller")
|
|
9
|
+
public class ApplicationContext {
|
|
10
|
+
public static void main(String[] args) {
|
|
11
|
+
SpringApplication.run(ApplicationContext.class, args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
package bharat.connect.biller.config;
|
|
2
|
+
|
|
3
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
4
|
+
import org.springframework.beans.factory.annotation.Qualifier;
|
|
5
|
+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
6
|
+
import org.springframework.context.annotation.Bean;
|
|
7
|
+
import org.springframework.context.annotation.Configuration;
|
|
8
|
+
import org.springframework.core.env.Environment;
|
|
9
|
+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
10
|
+
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
|
11
|
+
|
|
12
|
+
import javax.sql.DataSource;
|
|
13
|
+
|
|
14
|
+
@Configuration
|
|
15
|
+
@ConditionalOnProperty(prefix = "billing.provider", name = "type", havingValue = "postgres", matchIfMissing = true)
|
|
16
|
+
public class DatabaseConfig {
|
|
17
|
+
|
|
18
|
+
@Autowired
|
|
19
|
+
private Environment env;
|
|
20
|
+
|
|
21
|
+
@Bean
|
|
22
|
+
public DataSource dataSource() {
|
|
23
|
+
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
|
24
|
+
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
|
|
25
|
+
dataSource.setUrl(env.getProperty("spring.datasource.url"));
|
|
26
|
+
dataSource.setUsername(env.getProperty("spring.datasource.username"));
|
|
27
|
+
dataSource.setPassword(env.getProperty("spring.datasource.password"));
|
|
28
|
+
return dataSource;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Bean("jdbcNamedTemplate")
|
|
32
|
+
public NamedParameterJdbcTemplate jdbcNTemplate1(@Qualifier("dataSource") DataSource ds) {
|
|
33
|
+
return new NamedParameterJdbcTemplate(ds);
|
|
34
|
+
}
|
|
35
|
+
}
|
biller_cli/templates/biller-user-layer/src/main/java/bharat/connect/biller/config/WebCorsConfig.java
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
package bharat.connect.biller.config;
|
|
2
|
+
|
|
3
|
+
import org.springframework.beans.factory.annotation.Value;
|
|
4
|
+
import org.springframework.context.annotation.Configuration;
|
|
5
|
+
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
6
|
+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
7
|
+
|
|
8
|
+
@Configuration
|
|
9
|
+
public class WebCorsConfig implements WebMvcConfigurer {
|
|
10
|
+
|
|
11
|
+
@Value("${app.cors.allowed-origins:http://localhost:3000}")
|
|
12
|
+
private String[] allowedOrigins;
|
|
13
|
+
|
|
14
|
+
@Override
|
|
15
|
+
public void addCorsMappings(CorsRegistry registry) {
|
|
16
|
+
registry.addMapping("/**")
|
|
17
|
+
.allowedOrigins(allowedOrigins)
|
|
18
|
+
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
|
19
|
+
.allowedHeaders("*");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
package bharat.connect.biller.controller;
|
|
2
|
+
|
|
3
|
+
import bharat.connect.biller.common.API;
|
|
4
|
+
import bharat.connect.biller.common.CommonConstants;
|
|
5
|
+
import bharat.connect.biller.common.CommonUtils;
|
|
6
|
+
import bharat.connect.biller.service.BillPaymentService;
|
|
7
|
+
import bharat.connect.biller.service.BillFetchService;
|
|
8
|
+
import bharat.connect.biller.service.HeartbeatService;
|
|
9
|
+
import org.bbps.schema.Ack;
|
|
10
|
+
import org.bbps.schema.BillFetchRequest;
|
|
11
|
+
import org.bbps.schema.BillPaymentRequest;
|
|
12
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
13
|
+
import org.springframework.http.HttpStatus;
|
|
14
|
+
import org.springframework.http.MediaType;
|
|
15
|
+
import org.springframework.http.ResponseEntity;
|
|
16
|
+
import org.springframework.web.bind.annotation.*;
|
|
17
|
+
|
|
18
|
+
import jakarta.xml.bind.JAXBContext;
|
|
19
|
+
import jakarta.xml.bind.JAXBException;
|
|
20
|
+
import jakarta.xml.bind.Marshaller;
|
|
21
|
+
import java.io.StringWriter;
|
|
22
|
+
|
|
23
|
+
@RestController
|
|
24
|
+
@RequestMapping("/")
|
|
25
|
+
public class BbpsRequestController {
|
|
26
|
+
|
|
27
|
+
@Autowired
|
|
28
|
+
private BillFetchService billFetchService;
|
|
29
|
+
|
|
30
|
+
@Autowired
|
|
31
|
+
private BillPaymentService billPaymentService;
|
|
32
|
+
|
|
33
|
+
@Autowired
|
|
34
|
+
private HeartbeatService heartbeatService;
|
|
35
|
+
|
|
36
|
+
@RequestMapping(value = "/BillFetchRequest/1.0/urn:referenceId:{referenceId}", method = RequestMethod.POST, produces = MediaType.APPLICATION_XML_VALUE)
|
|
37
|
+
public Ack billFetchRequest(@RequestBody BillFetchRequest fetchRequest, @PathVariable("referenceId") String referenceId) {
|
|
38
|
+
System.out.println("====================received bill fetch request===============");
|
|
39
|
+
printXml(fetchRequest, BillFetchRequest.class, "BillFetchRequest XML");
|
|
40
|
+
if(fetchRequest != null && fetchRequest.getHead().getRefId()!=null && !fetchRequest.getHead().getRefId().isEmpty()){
|
|
41
|
+
billFetchService.processBillFetchAsync(fetchRequest,fetchRequest.getHead().getRefId());
|
|
42
|
+
}
|
|
43
|
+
fetchRequest.getBillDetails().getCustomerParams().getTags().stream().forEach(a -> System.out.println(a.getName() +" - "+a.getValue()));
|
|
44
|
+
|
|
45
|
+
Ack ack = new Ack();
|
|
46
|
+
API action = API.FETCH_REQUEST;
|
|
47
|
+
ack.setRefId(fetchRequest.getHead().getRefId());
|
|
48
|
+
ack.setApi(action.name());
|
|
49
|
+
ack.setTs(CommonUtils.getFormattedCurrentTimestamp());
|
|
50
|
+
ack.setRspCd(CommonConstants.RESP_SUCCESS_MSG);
|
|
51
|
+
printXml(ack, Ack.class, "BillFetchRequest ACK");
|
|
52
|
+
return ack;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@RequestMapping(value = "/BillPaymentRequest/1.0/urn:referenceId:{referenceId}", method = RequestMethod.POST, produces = MediaType.APPLICATION_XML_VALUE)
|
|
56
|
+
public Ack billPaymentRequest(@RequestBody BillPaymentRequest paymentRequest, @PathVariable("referenceId") String referenceId) {
|
|
57
|
+
System.out.println("====================received bill payment request===============");
|
|
58
|
+
printXml(paymentRequest, BillPaymentRequest.class, "BillPaymentRequest XML");
|
|
59
|
+
|
|
60
|
+
if (paymentRequest != null && paymentRequest.getHead() != null && paymentRequest.getHead().getRefId() != null && !paymentRequest.getHead().getRefId().isEmpty()) {
|
|
61
|
+
billPaymentService.processBillPaymentAsync(paymentRequest, paymentRequest.getHead().getRefId());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Ack ack = new Ack();
|
|
65
|
+
API action = API.PAYMENT_REQUEST;
|
|
66
|
+
ack.setRefId(paymentRequest.getHead().getRefId());
|
|
67
|
+
ack.setApi(action.name());
|
|
68
|
+
ack.setTs(CommonUtils.getFormattedCurrentTimestamp());
|
|
69
|
+
ack.setRspCd(CommonConstants.RESP_SUCCESS_MSG);
|
|
70
|
+
printXml(ack, Ack.class, "BillPaymentRequest ACK");
|
|
71
|
+
return ack;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@RequestMapping(value = "/heartbeat", method = RequestMethod.GET)
|
|
75
|
+
public String billFetchRequest() {
|
|
76
|
+
return heartbeatService.sendHeartbeat();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@RequestMapping(value = "/health", method = RequestMethod.GET)
|
|
80
|
+
public ResponseEntity<?> checkHealthStatus() {
|
|
81
|
+
return new ResponseEntity<>(HttpStatus.OK);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private void printXml(Object payload, Class<?> payloadClass, String label) {
|
|
85
|
+
try {
|
|
86
|
+
JAXBContext context = JAXBContext.newInstance(payloadClass);
|
|
87
|
+
Marshaller marshaller = context.createMarshaller();
|
|
88
|
+
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
|
89
|
+
StringWriter sw = new StringWriter();
|
|
90
|
+
marshaller.marshal(payload, sw);
|
|
91
|
+
System.out.println("=============== " + label + " ===============");
|
|
92
|
+
System.out.println(sw);
|
|
93
|
+
} catch (JAXBException e) {
|
|
94
|
+
e.printStackTrace();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package bharat.connect.biller.dao.impl;
|
|
2
|
+
|
|
3
|
+
import bharat.connect.biller.dao.BillFetchDao;
|
|
4
|
+
import bharat.connect.biller.model.BillDetails;
|
|
5
|
+
import org.bbps.schema.CustomerParamsType;
|
|
6
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
7
|
+
import org.springframework.beans.factory.annotation.Qualifier;
|
|
8
|
+
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
|
9
|
+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
10
|
+
import org.springframework.stereotype.Repository;
|
|
11
|
+
|
|
12
|
+
import java.util.List;
|
|
13
|
+
|
|
14
|
+
@Repository
|
|
15
|
+
public class BillFetchDaoImpl implements BillFetchDao {
|
|
16
|
+
|
|
17
|
+
@Autowired
|
|
18
|
+
@Qualifier(value = "jdbcNamedTemplate")
|
|
19
|
+
private NamedParameterJdbcTemplate jdbcNamedTemplate;
|
|
20
|
+
|
|
21
|
+
@Override
|
|
22
|
+
public BillDetails findLatestUnpaidByParam(String paramName, String paramValue) {
|
|
23
|
+
String sql = """
|
|
24
|
+
SELECT bill_id, customer_param_name, customer_param_type, customer_param_value,
|
|
25
|
+
bill_amount, bill_date, due_date, bill_number, bill_period, bill_status,
|
|
26
|
+
additional_info, created_at, updated_at
|
|
27
|
+
FROM bill_details
|
|
28
|
+
WHERE customer_param_name = :paramName
|
|
29
|
+
AND customer_param_value = :paramValue
|
|
30
|
+
AND bill_status = 'UNPAID'
|
|
31
|
+
ORDER BY due_date NULLS LAST, bill_date DESC, bill_id DESC
|
|
32
|
+
LIMIT 1
|
|
33
|
+
""";
|
|
34
|
+
|
|
35
|
+
MapSqlParameterSource params = new MapSqlParameterSource().addValue("paramName", paramName).addValue("paramValue", paramValue);
|
|
36
|
+
|
|
37
|
+
List<BillDetails> list = jdbcNamedTemplate.query(sql, params, (rs, rowNum) -> {
|
|
38
|
+
BillDetails b = new BillDetails();
|
|
39
|
+
b.setBillId((long) rs.getInt("bill_id"));
|
|
40
|
+
b.setCustomerParamName(rs.getString("customer_param_name"));
|
|
41
|
+
b.setCustomerParamType(rs.getString("customer_param_type"));
|
|
42
|
+
b.setCustomerParamValue(rs.getString("customer_param_value"));
|
|
43
|
+
b.setBillAmount(rs.getBigDecimal("bill_amount"));
|
|
44
|
+
var billDate = rs.getDate("bill_date");
|
|
45
|
+
if (billDate != null) b.setBillDate(billDate.toLocalDate());
|
|
46
|
+
var dueDate = rs.getDate("due_date");
|
|
47
|
+
if (dueDate != null) b.setDueDate(dueDate.toLocalDate());
|
|
48
|
+
b.setBillNumber(rs.getString("bill_number"));
|
|
49
|
+
b.setBillPeriod(rs.getString("bill_period"));
|
|
50
|
+
b.setBillStatus(rs.getString("bill_status"));
|
|
51
|
+
b.setAdditionalInfo(rs.getString("additional_info"));
|
|
52
|
+
var created = rs.getTimestamp("created_at");
|
|
53
|
+
if (created != null) b.setCreatedAt(created.toLocalDateTime());
|
|
54
|
+
var updated = rs.getTimestamp("updated_at");
|
|
55
|
+
if (updated != null) b.setUpdatedAt(updated.toLocalDateTime());
|
|
56
|
+
return b;
|
|
57
|
+
});
|
|
58
|
+
if (list.isEmpty()) return null;
|
|
59
|
+
return list.get(0);
|
|
60
|
+
}
|
|
61
|
+
@Override
|
|
62
|
+
public BillDetails findLatestUnpaidBillByCustomerParams(CustomerParamsType customerParamsType) {
|
|
63
|
+
List<CustomerParamsType.Tag> tags = customerParamsType.getTags();
|
|
64
|
+
if (tags == null || tags.isEmpty()) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
StringBuilder sql = new StringBuilder("""
|
|
68
|
+
SELECT bill_id, customer_param_name, customer_param_type, customer_param_value,
|
|
69
|
+
bill_amount, bill_date, due_date, bill_number, bill_period, bill_status,
|
|
70
|
+
additional_info, created_at, updated_at
|
|
71
|
+
FROM bill_details
|
|
72
|
+
WHERE bill_status = 'UNPAID'
|
|
73
|
+
""");
|
|
74
|
+
|
|
75
|
+
MapSqlParameterSource params = new MapSqlParameterSource();
|
|
76
|
+
|
|
77
|
+
// Build the OR group: ( (name=:n0 AND value=:v0) OR (name=:n1 AND value=:v1) OR ... )
|
|
78
|
+
boolean addedAny = false;
|
|
79
|
+
for (int i = 0; i < tags.size(); i++) {
|
|
80
|
+
CustomerParamsType.Tag t = tags.get(i);
|
|
81
|
+
if (t == null) continue;
|
|
82
|
+
String name = (t.getName() == null) ? null : t.getName().trim();
|
|
83
|
+
String value = (t.getValue() == null) ? null : t.getValue().trim();
|
|
84
|
+
if (name == null || name.isEmpty() || value == null || value.isEmpty()) continue;
|
|
85
|
+
|
|
86
|
+
String nKey = "name" + i;
|
|
87
|
+
String vKey = "value" + i;
|
|
88
|
+
params.addValue(nKey, name);
|
|
89
|
+
params.addValue(vKey, value);
|
|
90
|
+
|
|
91
|
+
sql.append(addedAny ? " OR " : " AND (");
|
|
92
|
+
sql.append("(customer_param_name = :").append(nKey).append(" AND customer_param_value = :").append(vKey).append(")");
|
|
93
|
+
addedAny = true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (addedAny) {
|
|
97
|
+
sql.append(")");
|
|
98
|
+
} else {
|
|
99
|
+
// All tags were blank/null — nothing meaningful to filter on
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
sql.append("""
|
|
104
|
+
ORDER BY due_date NULLS LAST, bill_date DESC, bill_id DESC
|
|
105
|
+
LIMIT 1
|
|
106
|
+
""");
|
|
107
|
+
|
|
108
|
+
List<BillDetails> list = jdbcNamedTemplate.query(sql.toString(), params, (rs, rowNum) -> {
|
|
109
|
+
BillDetails b = new BillDetails();
|
|
110
|
+
b.setBillId((long) rs.getInt("bill_id"));
|
|
111
|
+
b.setCustomerParamName(rs.getString("customer_param_name"));
|
|
112
|
+
b.setCustomerParamType(rs.getString("customer_param_type"));
|
|
113
|
+
b.setCustomerParamValue(rs.getString("customer_param_value"));
|
|
114
|
+
b.setBillAmount(rs.getBigDecimal("bill_amount"));
|
|
115
|
+
|
|
116
|
+
var billDate = rs.getDate("bill_date");
|
|
117
|
+
if (billDate != null) b.setBillDate(billDate.toLocalDate());
|
|
118
|
+
var dueDate = rs.getDate("due_date");
|
|
119
|
+
if (dueDate != null) b.setDueDate(dueDate.toLocalDate());
|
|
120
|
+
|
|
121
|
+
b.setBillNumber(rs.getString("bill_number"));
|
|
122
|
+
b.setBillPeriod(rs.getString("bill_period"));
|
|
123
|
+
b.setBillStatus(rs.getString("bill_status"));
|
|
124
|
+
b.setAdditionalInfo(rs.getString("additional_info"));
|
|
125
|
+
|
|
126
|
+
var created = rs.getTimestamp("created_at");
|
|
127
|
+
if (created != null) b.setCreatedAt(created.toLocalDateTime());
|
|
128
|
+
var updated = rs.getTimestamp("updated_at");
|
|
129
|
+
if (updated != null) b.setUpdatedAt(updated.toLocalDateTime());
|
|
130
|
+
|
|
131
|
+
return b;
|
|
132
|
+
});
|
|
133
|
+
return list.isEmpty() ? null : list.get(0);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package bharat.connect.biller.dao.impl;
|
|
2
|
+
|
|
3
|
+
import bharat.connect.biller.dao.BillPaymentDao;
|
|
4
|
+
import org.bbps.schema.CustomerParamsType;
|
|
5
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
6
|
+
import org.springframework.beans.factory.annotation.Qualifier;
|
|
7
|
+
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
|
8
|
+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
9
|
+
import org.springframework.stereotype.Repository;
|
|
10
|
+
import org.springframework.transaction.annotation.Transactional;
|
|
11
|
+
|
|
12
|
+
import java.math.BigDecimal;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
|
|
15
|
+
@Repository
|
|
16
|
+
public class BillPaymentDaoImpl implements BillPaymentDao {
|
|
17
|
+
|
|
18
|
+
@Autowired
|
|
19
|
+
@Qualifier(value = "jdbcNamedTemplate")
|
|
20
|
+
private NamedParameterJdbcTemplate jdbcNamedTemplate;
|
|
21
|
+
|
|
22
|
+
@Transactional
|
|
23
|
+
@Override
|
|
24
|
+
public boolean markBillPaidAndRecordTransaction(CustomerParamsType customerParams,
|
|
25
|
+
long billId,
|
|
26
|
+
String bbpsTxnRef,
|
|
27
|
+
BigDecimal amountPaid,
|
|
28
|
+
String paymentMode) {
|
|
29
|
+
List<CustomerParamsType.Tag> tags = customerParams.getTags();
|
|
30
|
+
if (tags == null || tags.isEmpty()) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
MapSqlParameterSource updateParams = new MapSqlParameterSource();
|
|
35
|
+
|
|
36
|
+
// Build customer-params matching clause (same pattern as BillFetchDaoImpl)
|
|
37
|
+
StringBuilder subWhere = new StringBuilder("bill_status = 'UNPAID'");
|
|
38
|
+
boolean addedAny = false;
|
|
39
|
+
for (int i = 0; i < tags.size(); i++) {
|
|
40
|
+
CustomerParamsType.Tag t = tags.get(i);
|
|
41
|
+
if (t == null) continue;
|
|
42
|
+
String name = (t.getName() == null) ? null : t.getName().trim();
|
|
43
|
+
String value = (t.getValue() == null) ? null : t.getValue().trim();
|
|
44
|
+
if (name == null || name.isEmpty() || value == null || value.isEmpty()) continue;
|
|
45
|
+
|
|
46
|
+
String nKey = "name" + i;
|
|
47
|
+
String vKey = "value" + i;
|
|
48
|
+
updateParams.addValue(nKey, name);
|
|
49
|
+
updateParams.addValue(vKey, value);
|
|
50
|
+
|
|
51
|
+
subWhere.append(addedAny ? " OR " : " AND (");
|
|
52
|
+
subWhere.append("(customer_param_name = :").append(nKey)
|
|
53
|
+
.append(" AND customer_param_value = :").append(vKey).append(")");
|
|
54
|
+
addedAny = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!addedAny) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
subWhere.append(")");
|
|
61
|
+
|
|
62
|
+
// Step 1: UPDATE bill_details to PAID, searched by customer params
|
|
63
|
+
String updateSql = """
|
|
64
|
+
UPDATE bill_details
|
|
65
|
+
SET bill_status = 'PAID',
|
|
66
|
+
updated_at = now()
|
|
67
|
+
WHERE bill_id = (
|
|
68
|
+
SELECT bill_id FROM bill_details
|
|
69
|
+
WHERE %s
|
|
70
|
+
ORDER BY due_date NULLS LAST, bill_date DESC, bill_id DESC
|
|
71
|
+
LIMIT 1
|
|
72
|
+
)
|
|
73
|
+
""".formatted(subWhere);
|
|
74
|
+
|
|
75
|
+
int updatedRows = jdbcNamedTemplate.update(updateSql, updateParams);
|
|
76
|
+
if (updatedRows <= 0) {
|
|
77
|
+
System.out.println("markBillPaidAndRecordTransaction: UPDATE matched 0 rows. No UNPAID bill for given customer params.");
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
System.out.println("markBillPaidAndRecordTransaction: bill_details updated to PAID (" + updatedRows + " row(s)).");
|
|
81
|
+
|
|
82
|
+
// Step 2: INSERT into payment_transactions (same transaction — rolls back UPDATE if this fails)
|
|
83
|
+
String insertSql = """
|
|
84
|
+
INSERT INTO payment_transactions (bill_id, bbps_txn_ref, amount_paid, payment_mode)
|
|
85
|
+
VALUES (:billId, :bbpsTxnRef, :amountPaid, :paymentMode)
|
|
86
|
+
""";
|
|
87
|
+
|
|
88
|
+
MapSqlParameterSource insertParams = new MapSqlParameterSource()
|
|
89
|
+
.addValue("billId", billId)
|
|
90
|
+
.addValue("bbpsTxnRef", bbpsTxnRef)
|
|
91
|
+
.addValue("amountPaid", amountPaid)
|
|
92
|
+
.addValue("paymentMode", paymentMode);
|
|
93
|
+
|
|
94
|
+
int inserted = jdbcNamedTemplate.update(insertSql, insertParams);
|
|
95
|
+
System.out.println("markBillPaidAndRecordTransaction: payment_transactions inserted=" + inserted
|
|
96
|
+
+ " for bill_id=" + billId + ", bbpsTxnRef=" + bbpsTxnRef);
|
|
97
|
+
|
|
98
|
+
return updatedRows > 0 && inserted > 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package bharat.connect.biller.provider;
|
|
2
|
+
|
|
3
|
+
import bharat.connect.biller.provider.impl.CsvBillingProvider;
|
|
4
|
+
import bharat.connect.biller.provider.impl.ExcelBillingProvider;
|
|
5
|
+
import bharat.connect.biller.provider.impl.PostgresBillingProvider;
|
|
6
|
+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
7
|
+
import org.springframework.beans.factory.ObjectProvider;
|
|
8
|
+
import org.springframework.context.annotation.Bean;
|
|
9
|
+
import org.springframework.context.annotation.Configuration;
|
|
10
|
+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
|
11
|
+
|
|
12
|
+
@Configuration
|
|
13
|
+
@EnableConfigurationProperties(BillingProviderProperties.class)
|
|
14
|
+
public class BillingProviderConfig {
|
|
15
|
+
|
|
16
|
+
@Bean
|
|
17
|
+
public BillingProvider billingProvider(BillingProviderProperties properties,
|
|
18
|
+
ObjectProvider<NamedParameterJdbcTemplate> jdbcNamedTemplateProvider) {
|
|
19
|
+
String type = properties.getType() == null ? "postgres" : properties.getType().trim().toLowerCase();
|
|
20
|
+
return switch (type) {
|
|
21
|
+
case "csv" -> new CsvBillingProvider(properties);
|
|
22
|
+
case "excel" -> new ExcelBillingProvider(properties);
|
|
23
|
+
case "postgres" -> new PostgresBillingProvider(requireJdbcTemplate(jdbcNamedTemplateProvider.getIfAvailable()), properties);
|
|
24
|
+
default -> throw new IllegalArgumentException("Unsupported billing.provider.type: " + type);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private NamedParameterJdbcTemplate requireJdbcTemplate(NamedParameterJdbcTemplate jdbcNamedTemplate) {
|
|
29
|
+
if (jdbcNamedTemplate == null) {
|
|
30
|
+
throw new IllegalStateException("NamedParameterJdbcTemplate bean missing for postgres provider.");
|
|
31
|
+
}
|
|
32
|
+
return jdbcNamedTemplate;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
package bharat.connect.biller.provider;
|
|
2
|
+
|
|
3
|
+
import lombok.Getter;
|
|
4
|
+
import lombok.Setter;
|
|
5
|
+
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
6
|
+
|
|
7
|
+
@Getter
|
|
8
|
+
@Setter
|
|
9
|
+
@ConfigurationProperties(prefix = "billing.provider")
|
|
10
|
+
public class BillingProviderProperties {
|
|
11
|
+
private String type = "postgres";
|
|
12
|
+
private String dateFormat = "yyyy-MM-dd";
|
|
13
|
+
|
|
14
|
+
private Csv csv = new Csv();
|
|
15
|
+
private Excel excel = new Excel();
|
|
16
|
+
private Postgres postgres = new Postgres();
|
|
17
|
+
|
|
18
|
+
@Getter
|
|
19
|
+
@Setter
|
|
20
|
+
public static class Csv {
|
|
21
|
+
private String path;
|
|
22
|
+
private String paymentLogPath;
|
|
23
|
+
private String delimiter = ",";
|
|
24
|
+
private Columns columns = new Columns();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Getter
|
|
28
|
+
@Setter
|
|
29
|
+
public static class Excel {
|
|
30
|
+
private String path;
|
|
31
|
+
private String sheetName = "Sheet1";
|
|
32
|
+
private String paymentLogPath;
|
|
33
|
+
private Columns columns = new Columns();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Getter
|
|
37
|
+
@Setter
|
|
38
|
+
public static class Columns {
|
|
39
|
+
private String billId = "bill_id";
|
|
40
|
+
private String customerParamName = "customer_param_name";
|
|
41
|
+
private String customerParamValue = "customer_param_value";
|
|
42
|
+
private String customerParamType = "customer_param_type";
|
|
43
|
+
private String billAmount = "bill_amount";
|
|
44
|
+
private String billDate = "bill_date";
|
|
45
|
+
private String dueDate = "due_date";
|
|
46
|
+
private String billNumber = "bill_number";
|
|
47
|
+
private String billPeriod = "bill_period";
|
|
48
|
+
private String billStatus = "bill_status";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Getter
|
|
52
|
+
@Setter
|
|
53
|
+
public static class Postgres {
|
|
54
|
+
private Tables tables = new Tables();
|
|
55
|
+
private BillColumns billColumns = new BillColumns();
|
|
56
|
+
private PaymentColumns paymentColumns = new PaymentColumns();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Getter
|
|
60
|
+
@Setter
|
|
61
|
+
public static class Tables {
|
|
62
|
+
private String billDetails = "bill_details";
|
|
63
|
+
private String paymentTransactions = "payment_transactions";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Getter
|
|
67
|
+
@Setter
|
|
68
|
+
public static class BillColumns {
|
|
69
|
+
private String billId = "bill_id";
|
|
70
|
+
private String customerParamName = "customer_param_name";
|
|
71
|
+
private String customerParamType = "customer_param_type";
|
|
72
|
+
private String customerParamValue = "customer_param_value";
|
|
73
|
+
private String billAmount = "bill_amount";
|
|
74
|
+
private String billDate = "bill_date";
|
|
75
|
+
private String dueDate = "due_date";
|
|
76
|
+
private String billNumber = "bill_number";
|
|
77
|
+
private String billPeriod = "bill_period";
|
|
78
|
+
private String billStatus = "bill_status";
|
|
79
|
+
private String additionalInfo = "additional_info";
|
|
80
|
+
private String createdAt = "created_at";
|
|
81
|
+
private String updatedAt = "updated_at";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Getter
|
|
85
|
+
@Setter
|
|
86
|
+
public static class PaymentColumns {
|
|
87
|
+
private String billId = "bill_id";
|
|
88
|
+
private String bbpsTxnRef = "bbps_txn_ref";
|
|
89
|
+
private String amountPaid = "amount_paid";
|
|
90
|
+
private String paymentMode = "payment_mode";
|
|
91
|
+
}
|
|
92
|
+
}
|