浏览代码

update report

tags/Baseline_30082024_BACKEND_UAT
cyril.tsui 1年前
父节点
当前提交
04e9594feb
共有 15 个文件被更改,包括 306 次插入110 次删除
  1. +0
    -97
      src/main/java/com/ffii/tsms/modules/common/service/ExcelReportService.kt
  2. +43
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt
  3. +9
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt
  4. +2
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt
  5. +2
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt
  6. +1
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/MilestonePaymentRepository.kt
  7. +1
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/Project.kt
  8. +11
    -3
      src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt
  9. +160
    -0
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  10. +19
    -9
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  11. +1
    -1
      src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt
  12. +39
    -0
      src/main/resources/db/changelog/changes/20240503_01_cyril/01_create_invoice.sql
  13. +9
    -0
      src/main/resources/db/changelog/changes/20240503_01_cyril/02_update_invoice.sql
  14. +9
    -0
      src/main/resources/db/changelog/changes/20240503_01_cyril/03_update_invoice.sql
  15. 二进制
      src/main/resources/templates/report/EX02_Project Cash Flow Report.xlsx

+ 0
- 97
src/main/java/com/ffii/tsms/modules/common/service/ExcelReportService.kt 查看文件

@@ -1,97 +0,0 @@
package com.ffii.tsms.modules.common.service

import com.ffii.tsms.modules.project.entity.Project
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.CellStyle
import org.apache.poi.ss.usermodel.HorizontalAlignment
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.ss.util.CellRangeAddress
import org.apache.poi.ss.util.CellUtil
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

@Service
open class ExcelReportService {
private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd")
private val FORMATTED_TODAY = LocalDate.now().format(DATE_FORMATTER)

private val EX02_PROJECT_CASH_FLOW_REPORT = "templates/report/EX02_Project Cash Flow Report.xlsx"

// ==============================|| GENERATE REPORT ||============================== //
@Throws(IOException::class)
fun generateEX02ProjectCashFlowReport(project: Project): ByteArray {
// Generate the Excel report with query results
val workbook: Workbook = createEX02ProjectCashFlowReport(project, EX02_PROJECT_CASH_FLOW_REPORT)

// Write the workbook to a ByteArrayOutputStream
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream)
workbook.close()

return outputStream.toByteArray()
}

// ==============================|| CREATE REPORT ||============================== //
@Throws(IOException::class)
private fun createEX02ProjectCashFlowReport(
project: Project,
templatePath: String,
): Workbook {
// please create a new function for each report template
val resource = ClassPathResource(templatePath)
val templateInputStream = resource.inputStream
val workbook: Workbook = XSSFWorkbook(templateInputStream)

val sheet: Sheet = workbook.getSheetAt(0)

// val alignLeftStyle: CellStyle = workbook.createCellStyle().apply {
// alignment = HorizontalAlignment.LEFT // Set the alignment to left
// }
//
// val alignRightStyle: CellStyle = workbook.createCellStyle().apply {
// alignment = HorizontalAlignment.RIGHT // Set the alignment to right
// }

var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field
var columnIndex = 2
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(FORMATTED_TODAY)
}

rowIndex = 2
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(project.code)
}

rowIndex = 3
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(project.name)
}

rowIndex = 4
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(if (project.customer?.name == null) "N/A" else project.customer?.name)
}

rowIndex = 5
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(if (project.teamLead?.team?.name == null) "N/A" else project.teamLead?.team?.name)
}

rowIndex = 9
sheet.getRow(rowIndex).apply {
getCell(1).setCellValue(project.expectedTotalFee!! * 0.8)
getCell(2).setCellValue(project.expectedTotalFee!!)
}

return workbook
}
}

+ 43
- 0
src/main/java/com/ffii/tsms/modules/project/entity/Invoice.kt 查看文件

@@ -0,0 +1,43 @@
package com.ffii.tsms.modules.project.entity

import com.ffii.core.entity.BaseEntity
import com.ffii.tsms.modules.data.entity.Customer
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.JoinColumn
import jakarta.persistence.ManyToOne
import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull
import java.time.LocalDate

@Entity
@Table(name = "invoice")
open class Invoice : BaseEntity<Long>(){

@NotNull
@Column(name = "invoiceNo", length = 45)
open var invoiceNo: String? = null

@NotNull
@ManyToOne
@JoinColumn(name = "milestonePaymentId")
open var milestonePayment: MilestonePayment? = null

@NotNull
@Column(name = "invoiceDate")
open var invoiceDate: LocalDate? = null

@NotNull
@Column(name = "dueDate")
open var dueDate: LocalDate? = null

@Column(name = "receiptDate")
open var receiptDate: LocalDate? = null

@NotNull
@Column(name = "unpaidAmount")
open var unpaidAmount: Double? = null

@Column(name = "paidAmount")
open var paidAmount: Double? = null
}

+ 9
- 0
src/main/java/com/ffii/tsms/modules/project/entity/InvoiceRepository.kt 查看文件

@@ -0,0 +1,9 @@
package com.ffii.tsms.modules.project.entity

import com.ffii.core.support.AbstractRepository

interface InvoiceRepository : AbstractRepository<Invoice, Long> {

fun findAllByPaidAmountIsNotNullAndMilestonePaymentIn(milestonePayment: List<MilestonePayment>): List<Invoice>

}

+ 2
- 0
src/main/java/com/ffii/tsms/modules/project/entity/Milestone.kt 查看文件

@@ -1,5 +1,6 @@
package com.ffii.tsms.modules.project.entity package com.ffii.tsms.modules.project.entity


import com.fasterxml.jackson.annotation.JsonManagedReference
import com.ffii.core.entity.IdEntity import com.ffii.core.entity.IdEntity
import jakarta.persistence.* import jakarta.persistence.*
import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.NotNull
@@ -15,6 +16,7 @@ open class Milestone : IdEntity<Long>() {
@Column(name = "description") @Column(name = "description")
open var description: String? = null open var description: String? = null


@JsonManagedReference
@OneToMany(mappedBy = "milestone", cascade = [CascadeType.ALL], orphanRemoval = true) @OneToMany(mappedBy = "milestone", cascade = [CascadeType.ALL], orphanRemoval = true)
open var milestonePayments: MutableList<MilestonePayment> = mutableListOf() open var milestonePayments: MutableList<MilestonePayment> = mutableListOf()




+ 2
- 0
src/main/java/com/ffii/tsms/modules/project/entity/MilestonePayment.kt 查看文件

@@ -1,5 +1,6 @@
package com.ffii.tsms.modules.project.entity package com.ffii.tsms.modules.project.entity


import com.fasterxml.jackson.annotation.JsonBackReference
import com.ffii.core.entity.IdEntity import com.ffii.core.entity.IdEntity
import jakarta.persistence.* import jakarta.persistence.*
import jakarta.validation.constraints.NotNull import jakarta.validation.constraints.NotNull
@@ -21,6 +22,7 @@ open class MilestonePayment : IdEntity<Long>() {
open var description: String? = null open var description: String? = null


@ManyToOne @ManyToOne
@JsonBackReference
@JoinColumn(name = "milestoneId") @JoinColumn(name = "milestoneId")
open var milestone: Milestone? = null open var milestone: Milestone? = null
} }

+ 1
- 0
src/main/java/com/ffii/tsms/modules/project/entity/MilestonePaymentRepository.kt 查看文件

@@ -3,4 +3,5 @@ package com.ffii.tsms.modules.project.entity;
import com.ffii.core.support.AbstractRepository import com.ffii.core.support.AbstractRepository


interface MilestonePaymentRepository : AbstractRepository<MilestonePayment, Long> { interface MilestonePaymentRepository : AbstractRepository<MilestonePayment, Long> {
fun findAllByMilestoneIn(milestones: List<Milestone>): List<MilestonePayment>
} }

+ 1
- 0
src/main/java/com/ffii/tsms/modules/project/entity/Project.kt 查看文件

@@ -1,5 +1,6 @@
package com.ffii.tsms.modules.project.entity package com.ffii.tsms.modules.project.entity


import com.fasterxml.jackson.annotation.JsonManagedReference
import com.ffii.core.entity.BaseEntity import com.ffii.core.entity.BaseEntity
import com.ffii.tsms.modules.data.entity.* import com.ffii.tsms.modules.data.entity.*
import jakarta.persistence.* import jakarta.persistence.*


+ 11
- 3
src/main/java/com/ffii/tsms/modules/project/service/InvoiceService.kt 查看文件

@@ -4,9 +4,8 @@ import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.AbstractIdEntityService import com.ffii.core.support.AbstractIdEntityService
import com.ffii.core.support.JdbcDao import com.ffii.core.support.JdbcDao
import com.ffii.core.utils.PdfUtils import com.ffii.core.utils.PdfUtils
import com.ffii.tsms.modules.project.entity.*


import com.ffii.tsms.modules.project.entity.MilestonePayment
import com.ffii.tsms.modules.project.entity.MilestonePaymentRepository
import com.ffii.tsms.modules.project.entity.projections.InvoicePDFReq import com.ffii.tsms.modules.project.entity.projections.InvoicePDFReq
import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo
import net.sf.jasperreports.engine.JasperCompileManager import net.sf.jasperreports.engine.JasperCompileManager
@@ -21,9 +20,18 @@ import java.time.format.DateTimeFormatter


@Service @Service
open class InvoiceService( open class InvoiceService(
private val invoiceRepository: InvoiceRepository,
private val milestoneRepository: MilestoneRepository,
private val milestonePaymentRepository: MilestonePaymentRepository, private val milestonePaymentRepository: MilestonePaymentRepository,
private val jdbcDao: JdbcDao, private val jdbcDao: JdbcDao,
) : AbstractIdEntityService<MilestonePayment, Long, MilestonePaymentRepository>(jdbcDao, milestonePaymentRepository){
) : AbstractIdEntityService<Invoice, Long, InvoiceRepository>(jdbcDao, invoiceRepository){

open fun findAllByProjectAndPaidAmountIsNotNull(project: Project): List<Invoice> {
val milestones = milestoneRepository.findAllByProject(project)
val milestonePayments = milestonePaymentRepository.findAllByMilestoneIn(milestones)
return invoiceRepository.findAllByPaidAmountIsNotNullAndMilestonePaymentIn(milestonePayments)
}

open fun allMilestonePayments(): List<Map<String, Any>> { open fun allMilestonePayments(): List<Map<String, Any>> {
val sql = StringBuilder(" select " val sql = StringBuilder(" select "
+ " mp.id, " + " mp.id, "


+ 160
- 0
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt 查看文件

@@ -0,0 +1,160 @@
package com.ffii.tsms.modules.report.service

import com.ffii.tsms.modules.project.entity.Invoice
import com.ffii.tsms.modules.project.entity.Project
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFDataFormat
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.core.io.ClassPathResource
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.time.LocalDate
import java.time.format.DateTimeFormatter

@Service
open class ReportService {
private val DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd")
private val FORMATTED_TODAY = LocalDate.now().format(DATE_FORMATTER)

private val PROJECT_CASH_FLOW_REPORT = "templates/report/EX02_Project Cash Flow Report.xlsx"

// ==============================|| GENERATE REPORT ||============================== //
@Throws(IOException::class)
fun generateProjectCashFlowReport(project: Project, invoices: List<Invoice>): ByteArray {
// Generate the Excel report with query results
val workbook: Workbook = createProjectCashFlowReport(project, invoices, PROJECT_CASH_FLOW_REPORT)

// Write the workbook to a ByteArrayOutputStream
val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream)
workbook.close()

return outputStream.toByteArray()
}

// ==============================|| CREATE REPORT ||============================== //
@Throws(IOException::class)
private fun createProjectCashFlowReport(
project: Project,
invoices: List<Invoice>,
templatePath: String,
): Workbook {
// please create a new function for each report template
val resource = ClassPathResource(templatePath)
val templateInputStream = resource.inputStream
val workbook: Workbook = XSSFWorkbook(templateInputStream)

val sheet: Sheet = workbook.getSheetAt(0)

// accounting style + comma style
val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)")

var rowIndex = 1 // Assuming the location is in (1,2), which is the report date field
var columnIndex = 2
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(FORMATTED_TODAY)
}

rowIndex = 2
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(project.code)
}

rowIndex = 3
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(project.name)
}

rowIndex = 4
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(if (project.customer?.name == null) "N/A" else project.customer?.name)
}

rowIndex = 5
sheet.getRow(rowIndex).getCell(columnIndex).apply {
setCellValue(if (project.teamLead?.team?.name == null) "N/A" else project.teamLead?.team?.name)
}

rowIndex = 9
sheet.getRow(rowIndex).apply {
getCell(1).apply {
setCellValue(project.expectedTotalFee!!)
cellStyle.dataFormat = accountingStyle
}

getCell(2).apply {
setCellValue(project.expectedTotalFee!! / 0.8)
cellStyle.dataFormat = accountingStyle
}
}

rowIndex = 10
val actualIncome = invoices.sumOf { invoice -> invoice.paidAmount!! }
sheet.getRow(rowIndex).apply {
getCell(1).apply {
// TODO: Replace by actual expenditure
setCellValue(actualIncome * 0.8)
cellStyle.dataFormat = accountingStyle
}

getCell(2).apply {
setCellValue(actualIncome)
cellStyle.dataFormat = accountingStyle
}
}

rowIndex = 11
sheet.getRow(rowIndex).apply {
getCell(1).apply {
// TODO: Replace by actual expenditure
cellFormula = "B10-B11"
cellStyle.dataFormat = accountingStyle
}

getCell(2).apply {
cellFormula = "C10-C11"
cellStyle.dataFormat = accountingStyle
}
}

// TODO: Add expenditure
// formula =IF(B17>0,D16-B17,D16+C17)
rowIndex = 15
val dateFormatter = DateTimeFormatter.ofPattern("MMM YYYY")
invoices.forEach { invoice: Invoice ->
sheet.getRow(rowIndex++).apply {
getCell(0).apply {
setCellValue(invoice.receiptDate!!.format(dateFormatter))
}

getCell(1).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}

getCell(2).apply {
setCellValue(invoice.paidAmount!!)
cellStyle.dataFormat = accountingStyle
}

getCell(3).apply {
val lastRow = rowIndex - 1
if (lastRow == 15) {
cellFormula = "C{currentRow}".replace("{currentRow}", rowIndex.toString())
} else {
cellFormula = "IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace("{currentRow}", rowIndex.toString()).replace("{lastRow}", lastRow.toString())
}
cellStyle.dataFormat = accountingStyle
}

getCell(4).apply {
setCellValue(invoice.milestonePayment!!.description!!)
}
}
}

return workbook
}
}

+ 19
- 9
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt 查看文件

@@ -1,36 +1,46 @@
package com.ffii.tsms.modules.report.web package com.ffii.tsms.modules.report.web


import com.ffii.tsms.modules.common.service.ExcelReportService
import com.ffii.tsms.modules.project.entity.ProjectRepository
import com.ffii.tsms.modules.report.web.model.EX02ProjectCashFlowReportRequest
import com.ffii.tsms.modules.project.entity.*
import com.ffii.tsms.modules.report.service.ReportService
import com.ffii.tsms.modules.project.service.InvoiceService
import com.ffii.tsms.modules.report.web.model.ProjectCashFlowReportRequest
import jakarta.validation.Valid import jakarta.validation.Valid
import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.ByteArrayResource
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.ServletRequestBindingException import org.springframework.web.bind.ServletRequestBindingException
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
import java.io.IOException import java.io.IOException
import java.time.LocalDate import java.time.LocalDate


@RestController @RestController
@RequestMapping("/reports") @RequestMapping("/reports")
class ReportController(private val excelReportService: ExcelReportService, private val projectRepository: ProjectRepository) {
class ReportController(private val invoiceRepository: InvoiceRepository, private val milestonePaymentRepository: MilestonePaymentRepository, private val excelReportService: ReportService, private val projectRepository: ProjectRepository, private val invoiceService: InvoiceService) {


@PostMapping("/EX02-ProjectCashFlowReport")
@PostMapping("/ProjectCashFlowReport")
@Throws(ServletRequestBindingException::class, IOException::class) @Throws(ServletRequestBindingException::class, IOException::class)
fun getEx02ProjectCashFlowReport(@RequestBody @Valid request: EX02ProjectCashFlowReportRequest): ResponseEntity<Resource> {
fun getProjectCashFlowReport(@RequestBody @Valid request: ProjectCashFlowReportRequest): ResponseEntity<Resource> {


val project = projectRepository.findById(request.projectId).orElseThrow() val project = projectRepository.findById(request.projectId).orElseThrow()
val invoices = invoiceService.findAllByProjectAndPaidAmountIsNotNull(project)


val reportResult: ByteArray = excelReportService.generateEX02ProjectCashFlowReport(project)
val reportResult: ByteArray = excelReportService.generateProjectCashFlowReport(project, invoices)
// val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") // val mediaType: MediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return ResponseEntity.ok() return ResponseEntity.ok()
// .contentType(mediaType) // .contentType(mediaType)
.header("filename", "EX02 - Project Cash Flow Report - " + LocalDate.now() + ".xlsx")
.header("filename", "Project Cash Flow Report - " + LocalDate.now() + ".xlsx")
.body(ByteArrayResource(reportResult)) .body(ByteArrayResource(reportResult))
} }

@GetMapping("/test/{id}")
fun test(@PathVariable id: Long): List<Invoice> {
val project = projectRepository.findById(id).orElseThrow()
return invoiceService.findAllByProjectAndPaidAmountIsNotNull(project)
}
} }

+ 1
- 1
src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt 查看文件

@@ -1,5 +1,5 @@
package com.ffii.tsms.modules.report.web.model package com.ffii.tsms.modules.report.web.model


data class EX02ProjectCashFlowReportRequest (
data class ProjectCashFlowReportRequest (
val projectId: Long val projectId: Long
) )

+ 39
- 0
src/main/resources/db/changelog/changes/20240503_01_cyril/01_create_invoice.sql 查看文件

@@ -0,0 +1,39 @@
-- liquibase formatted sql
-- changeset cyril:create invoice

CREATE TABLE `invoice` (
`id` INT NOT NULL AUTO_INCREMENT,
`version` INT NOT NULL DEFAULT '0',
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`createdBy` VARCHAR(30) NULL DEFAULT NULL,
`modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modifiedBy` VARCHAR(30) NULL DEFAULT NULL,
`deleted` TINYINT(1) NOT NULL DEFAULT '0',
`invoiceNo` VARCHAR(45) NOT NULL,
`projectId` INT NOT NULL,
`milestonePaymentId` INT NOT NULL,
`clientId` INT NOT NULL,
`invoiceDate` DATE NOT NULL,
`dueDate` DATE NOT NULL,
`receiptDate` DATE NULL,
`unpaidAmount` DECIMAL(16,2) NOT NULL,
`paidAmount` DECIMAL(16,2) NULL,
PRIMARY KEY (`id`),
INDEX `FK_INVOICE_ON_PROJECTID` (`projectId` ASC) VISIBLE,
INDEX `FK_INVOICE_ON_MILESTONEPAYMENTID` (`milestonePaymentId` ASC) VISIBLE,
INDEX `FK_INVOICE_ON_CLIENTID` (`clientId` ASC) VISIBLE,
CONSTRAINT `FK_INVOICE_ON_PROJECTID`
FOREIGN KEY (`projectId`)
REFERENCES `project` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_INVOICE_ON_MILESTONEPAYMENTID`
FOREIGN KEY (`milestonePaymentId`)
REFERENCES `milestone_payment` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_INVOICE_ON_CLIENTID`
FOREIGN KEY (`clientId`)
REFERENCES `customer` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);

+ 9
- 0
src/main/resources/db/changelog/changes/20240503_01_cyril/02_update_invoice.sql 查看文件

@@ -0,0 +1,9 @@
-- liquibase formatted sql
-- changeset cyril:update invoice

ALTER TABLE `invoice`
DROP FOREIGN KEY `FK_INVOICE_ON_CLIENTID`;
ALTER TABLE `invoice`
DROP COLUMN `clientId`,
DROP INDEX `FK_INVOICE_ON_CLIENTID` ;
;

+ 9
- 0
src/main/resources/db/changelog/changes/20240503_01_cyril/03_update_invoice.sql 查看文件

@@ -0,0 +1,9 @@
-- liquibase formatted sql
-- changeset cyril:update invoice

ALTER TABLE `invoice`
DROP FOREIGN KEY `FK_INVOICE_ON_PROJECTID`;
ALTER TABLE `invoice`
DROP COLUMN `projectId`,
DROP INDEX `FK_INVOICE_ON_PROJECTID` ;
;

二进制
src/main/resources/templates/report/EX02_Project Cash Flow Report.xlsx 查看文件


正在加载...
取消
保存