diff --git a/src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt b/src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt index 3adc636..0a7bee6 100644 --- a/src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt +++ b/src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt @@ -27,7 +27,6 @@ open class Invoice : BaseEntity(){ @Column(name = "invoiceDate") open var invoiceDate: LocalDate? = null - @NotNull @Column(name = "dueDate") open var dueDate: LocalDate? = null diff --git a/src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt b/src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt index fde8f71..2ce96fc 100644 --- a/src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt +++ b/src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt @@ -9,6 +9,8 @@ import com.ffii.tsms.modules.project.entity.projections.InvoiceInfo import com.ffii.tsms.modules.project.entity.projections.InvoicePDFReq import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo +import com.ffii.tsms.modules.project.web.models.EditInvoiceRequest +import com.ffii.tsms.modules.project.web.models.EditInvoiceResponse import com.ffii.tsms.modules.project.web.models.InvoiceResponse import net.sf.jasperreports.engine.JasperCompileManager import net.sf.jasperreports.engine.JasperReport @@ -22,6 +24,9 @@ import java.io.InputStream import java.math.BigDecimal import java.time.LocalDate import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.util.Optional +import kotlin.math.min @Service @@ -357,7 +362,7 @@ open class InvoiceService( // For checking mandatory field in each row val emptyRowList: MutableList = mutableListOf() // Beria cannot provide Payment Milestone when importing the invoice, so it cannot be checked and import to DB - val mandatoryColumns = listOf(0,1,10,11,12) // Mandatory Field in column 0,1,10,11,12 + val mandatoryColumns = listOf(0,1,2,3) // Mandatory Field in column 0,1,10,11,12 if (workbook == null) { return InvoiceResponse(false, "No Excel import", newProjectCodes, emptyRowList, invoicesResult, ArrayList(), ArrayList()) // if workbook is null @@ -412,17 +417,17 @@ open class InvoiceService( val invoice = Invoice().apply { invoiceNo = ExcelUtils.getCell(sheet, i, 0).toString() projectCode = ExcelUtils.getCell(sheet, i, 1).stringCellValue - projectName = ExcelUtils.getCell(sheet, i, 2).stringCellValue - team = ExcelUtils.getCell(sheet, i, 3).stringCellValue - stage = ExcelUtils.getCell(sheet, i, 4).numericCellValue.toString() - paymentMilestone = ExcelUtils.getCell(sheet, i, 5).stringCellValue - paymentMilestoneDate = ExcelUtils.getCell(sheet, i, 6).dateCellValue?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDate() - client = ExcelUtils.getCell(sheet, i, 7).stringCellValue - address = ExcelUtils.getCell(sheet, i, 8).stringCellValue - attention = ExcelUtils.getCell(sheet, i, 9).stringCellValue - invoiceDate = ExcelUtils.getCell(sheet, i, 10).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() - dueDate = ExcelUtils.getCell(sheet, i, 11).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() - issueAmount = ExcelUtils.getCell(sheet, i, 12).numericCellValue.toBigDecimal() +// projectName = ExcelUtils.getCell(sheet, i, 2).stringCellValue +// team = ExcelUtils.getCell(sheet, i, 3).stringCellValue +// stage = ExcelUtils.getCell(sheet, i, 4).numericCellValue.toString() +// paymentMilestone = ExcelUtils.getCell(sheet, i, 5).stringCellValue +// paymentMilestoneDate = ExcelUtils.getCell(sheet, i, 6).dateCellValue?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDate() +// client = ExcelUtils.getCell(sheet, i, 7).stringCellValue +// address = ExcelUtils.getCell(sheet, i, 8).stringCellValue +// attention = ExcelUtils.getCell(sheet, i, 9).stringCellValue + invoiceDate = ExcelUtils.getCell(sheet, i, 2).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() +// dueDate = ExcelUtils.getCell(sheet, i, 11).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() + issueAmount = ExcelUtils.getCell(sheet, i, 3).numericCellValue.toBigDecimal() // Beria cannot provide Payment Milestone when importing the invoice, so it cannot be checked and import to DB // this.milestonePayment = milestonePayment } @@ -443,7 +448,7 @@ open class InvoiceService( // For checking mandatory field in each row val emptyRowList: MutableList = mutableListOf() - val mandatoryColumns = listOf(0,1,4,5) // Mandatory Field in column 0,1,4,5 + val mandatoryColumns = listOf(0,1,2,3) // Mandatory Field in column 0,1,4,5 if (workbook == null) { return InvoiceResponse(false, "No Excel import", newProjectCodes, emptyRowList, invoicesResult, ArrayList(), ArrayList()) // if workbook is null @@ -502,8 +507,8 @@ open class InvoiceService( for (i in 2..sheet.lastRowNum){ val invoice = getInvoiceByInvoiceNo(ExcelUtils.getCell(sheet, i, 0).toString()) - invoice.paidAmount = ExcelUtils.getCell(sheet, i, 5).numericCellValue.toBigDecimal() - invoice.receiptDate = ExcelUtils.getCell(sheet, i, 4).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() + invoice.paidAmount = ExcelUtils.getCell(sheet, i, 3).numericCellValue.toBigDecimal() + invoice.receiptDate = ExcelUtils.getCell(sheet, i, 2).dateCellValue.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() saveAndFlush(invoice) } @@ -520,52 +525,77 @@ open class InvoiceService( val importInvoices: MutableList> = mutableListOf(); val sheet: Sheet = workbook.getSheetAt(1) - println(sheet.lastRowNum) - for(i in 3 until sheet.lastRowNum){ - val issueYear = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("B")).numericCellValue - val issueMonth = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("C")).numericCellValue - val issueDay = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("D")).numericCellValue - val adjustedYear = if (issueYear < 100) 2000 + issueYear else issueYear - val issueDate = convertToLocalDate(adjustedYear.toInt(), issueMonth.toInt(), issueDay.toInt()) - - val projectPrefix = getCellValue(sheet, i, convertAlphaToNumber("E") ) - val projectNo = getCellValue(sheet, i, convertAlphaToNumber("F") ) - val projectCode = "${projectPrefix}-${projectNo}" - println("${i}: ${projectCode}") - - val invoicePrefix1 = getCellValueWithBracket(sheet, i, convertAlphaToNumber("G") ) - val invoicePrefix2 = getCellValueWithBracket(sheet, i, convertAlphaToNumber("H") ) - val invoicePrefix3 = getCellValue(sheet, i, convertAlphaToNumber("I") ) - val invoicePrefix4 = getCellValue(sheet, i, convertAlphaToNumber("J") ) - // Put the cell into list, if cell is empty not join with "-" - val invoiceNo = listOf(projectCode, invoicePrefix1, invoicePrefix2, invoicePrefix3, invoicePrefix4) - .filter { it.isNotEmpty() } - .joinToString("-") - - val issuedAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("M")).numericCellValue - val canceledAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("N")).numericCellValue - val settleYear = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("Q")).numericCellValue - val settleMonth = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("R")).numericCellValue - val settleDay = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("S")).numericCellValue - val adjustedSettleYear = if (settleYear < 100) 2000 + settleYear else settleYear - val settleDate = convertToLocalDate(adjustedSettleYear.toInt(), settleMonth.toInt(), settleDay.toInt()) - val receivedAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("T")).numericCellValue - - val importInvoice: Map = mapOf( - "invoiceNo" to invoiceNo, - "projectCode" to projectCode, - "issuedAmount" to issuedAmount, - "canceledAmount" to canceledAmount, - "invoiceDate" to issueDate, - "receiptDate" to settleDate, - "receivedAmount" to receivedAmount, - ) - importInvoices.add(importInvoice) + val lastRow = sheet.lastRowNum + val physicalRows = sheet.physicalNumberOfRows + println(lastRow) + println(physicalRows) + + for(i in 3 until minOf(lastRow, physicalRows)){ + val row = sheet.getRow(i) + if(row != null){ + val issueYear = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("B")).numericCellValue + val issueMonth = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("C")).numericCellValue + val issueDay = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("D")).numericCellValue + val adjustedYear = if (issueYear < 100) 2000 + issueYear else issueYear + val issueDate = convertToLocalDate(adjustedYear.toInt(), issueMonth.toInt(), issueDay.toInt()) + + val projectPrefix = getCellValue(sheet, i, convertAlphaToNumber("E") ) // got error why + val projectNo = getCellValue(sheet, i, convertAlphaToNumber("F") ) + val projectCode = "${projectPrefix}-${projectNo}" + println("${i}: ${projectCode}") + + val invoicePrefix1 = getCellValueWithBracket(sheet, i, convertAlphaToNumber("G") ) + val invoicePrefix2 = getCellValueWithBracket(sheet, i, convertAlphaToNumber("H") ) + val invoicePrefix3 = getCellValue(sheet, i, convertAlphaToNumber("I") ) + val invoicePrefix4 = getCellValue(sheet, i, convertAlphaToNumber("J") ) + // Put the cell into list, if cell is empty not join with "-" + val invoiceNo = listOf(projectCode, invoicePrefix1, invoicePrefix2, invoicePrefix3, invoicePrefix4) + .filter { it.isNotEmpty() } + .joinToString("-") + + val issuedAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("M")).numericCellValue + val canceledAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("N")).numericCellValue + val settleYear = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("Q")).numericCellValue + val settleMonth = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("R")).numericCellValue + val settleDay = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("S")).numericCellValue + val adjustedSettleYear = if (settleYear < 100) 2000 + settleYear else settleYear + val settleDate = convertToLocalDate(adjustedSettleYear.toInt(), settleMonth.toInt(), settleDay.toInt()) + val receivedAmount = ExcelUtils.getCell(sheet, i, convertAlphaToNumber("T")).numericCellValue + + val importInvoice: Map = mapOf( + "invoiceNo" to invoiceNo, + "projectCode" to projectCode, + "issuedAmount" to issuedAmount.toBigDecimal().setScale(2), + "canceledAmount" to canceledAmount.toBigDecimal().setScale(2), + "invoiceDate" to issueDate, + "receiptDate" to settleDate, + "receivedAmount" to receivedAmount.toBigDecimal().setScale(2), + ) + importInvoices.add(importInvoice) + } } - println("invoiceRecords: $invoiceRecords") +// println("invoiceRecords: $invoiceRecords") + println("------------------------------------- intersect -------------------------------------") val (intersect, notIntersect) = importInvoices.partition { item -> + println("item---------------- $item") invoiceRecords.any { invoice -> + println("Start any") + println("invoice.invoiceDate-------------- ${invoice.invoiceDate}") + println("item[\"invoiceDate\"]-------------- ${item["invoiceDate"]}") + println(invoice.invoiceDate == item["invoiceDate"]) + println("----") + println("invoice.receiptDate-------------- ${invoice.receiptDate}") + println("item[\"receiptDate\"]-------------- ${item["receiptDate"]}") + print(invoice.receiptDate == item["receiptDate"]) + println("----") +// println("invoice.receivedAmount-------------- ${invoice.receivedAmount}") +// println("item[\"receivedAmount\"]-------------- ${item["receivedAmount"]}") +// println(invoice.receivedAmount == item["receivedAmount"]) +// println("----") +// println("invoice.issuedAmount-------------- ${invoice.issuedAmount}") +// println("item[\"issuedAmount\"]-------------- ${item["issuedAmount"]}") +// println(invoice.issuedAmount == item["issuedAmount"]) invoice.invoiceNo == item["invoiceNo"] && invoice.invoiceDate == item["invoiceDate"] && invoice.receiptDate == item["receiptDate"] && @@ -597,7 +627,7 @@ open class InvoiceService( fun getCellValueWithBracket(sheet: Sheet, rowIndex: Int, columnIndex: Int): String { val row = sheet.getRow(rowIndex) - val cell = row.getCell(columnIndex) + val cell = row.getCell(columnIndex) ?: return "" return when (cell.cellType) { CellType.NUMERIC -> "(${cell.numericCellValue.toInt()})" @@ -651,4 +681,43 @@ open class InvoiceService( return result } + open fun updateInvoiceDetail(editInvoiceRequest :EditInvoiceRequest): EditInvoiceResponse { + val invoice = repository.findById(editInvoiceRequest.id) + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + println("${editInvoiceRequest.issuedDate}, ${editInvoiceRequest.receiptDate}") + if (invoice.isPresent){ + val updateInvocie = invoice.get().apply { + invoiceNo = editInvoiceRequest.invoiceNo + issueAmount = editInvoiceRequest.issuedAmount + paidAmount = editInvoiceRequest.receivedAmount + invoiceDate = LocalDate.parse(editInvoiceRequest.issuedDate, formatter) + receiptDate = LocalDate.parse(editInvoiceRequest.receiptDate, formatter) + }.also { saveAndFlush(it) } + + return updateInvocie.let { + EditInvoiceResponse( + id = it.id, + invoiceNo = it.invoiceNo, + issuedAmount = it.issueAmount, + issuedDate = it.invoiceDate, + receiptDate = it.receiptDate, + receivedAmount = it.paidAmount, + message = "success", + error = null + ) + } + }else{ + return EditInvoiceResponse( + id = null, + invoiceNo = null, + issuedAmount = null, + issuedDate = null, + receiptDate = null, + receivedAmount = null, + message = "fail", + error = "invoice not found" + ) + } + } + } diff --git a/src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt b/src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt index c143adf..666c5cc 100644 --- a/src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt +++ b/src/main/java/com/ffii/tsms/modules/project/web/InvoiceController.kt @@ -7,6 +7,8 @@ import com.ffii.tsms.modules.project.entity.projections.InvoicePDFReq import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo import com.ffii.tsms.modules.project.service.InvoiceService import com.ffii.tsms.modules.project.service.ProjectsService +import com.ffii.tsms.modules.project.web.models.EditInvoiceRequest +import com.ffii.tsms.modules.project.web.models.EditInvoiceResponse import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import net.sf.jasperreports.engine.JasperExportManager @@ -138,4 +140,9 @@ class InvoiceController( // println("--------- OK -------------") return ResponseEntity.ok(invoiceService.importInvoices(workbook)) } + + @PostMapping("/update") + fun updateInvoiceDetail(@RequestBody req: EditInvoiceRequest): EditInvoiceResponse { + return invoiceService.updateInvoiceDetail(req) + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceRequest.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceRequest.kt new file mode 100644 index 0000000..0f27c4a --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceRequest.kt @@ -0,0 +1,13 @@ +package com.ffii.tsms.modules.project.web.models + +import java.math.BigDecimal +import java.time.LocalDate + +data class EditInvoiceRequest( + val id: Long, + val invoiceNo: String, + val issuedAmount: BigDecimal, + val issuedDate: String, + val receiptDate: String, + val receivedAmount: BigDecimal +) \ No newline at end of file diff --git a/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceResponse.kt b/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceResponse.kt new file mode 100644 index 0000000..da1bfb9 --- /dev/null +++ b/src/main/java/com/ffii/tsms/modules/project/web/models/EditInvoiceResponse.kt @@ -0,0 +1,15 @@ +package com.ffii.tsms.modules.project.web.models + +import java.math.BigDecimal +import java.time.LocalDate + +data class EditInvoiceResponse ( + val id: Long?, + val invoiceNo: String?, + val issuedAmount: BigDecimal?, + val issuedDate: LocalDate?, + val receiptDate: LocalDate?, + val receivedAmount: BigDecimal?, + val message: String?, + val error: String? +) \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/20240718_01_jasonT/01_alter_invoice_table_dueDate_nallable.sql b/src/main/resources/db/changelog/changes/20240718_01_jasonT/01_alter_invoice_table_dueDate_nallable.sql new file mode 100644 index 0000000..2da8a4f --- /dev/null +++ b/src/main/resources/db/changelog/changes/20240718_01_jasonT/01_alter_invoice_table_dueDate_nallable.sql @@ -0,0 +1,4 @@ +-- liquibase formatted sql +-- changeset jasonT:invoice, to align with latest Beria import issued invoice template + +ALTER TABLE tsmsdb.invoice MODIFY COLUMN dueDate date NULL;