mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-21 13:55:43 +00:00
308 lines
6.9 KiB
Go
308 lines
6.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/xuri/excelize/v2"
|
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
)
|
|
|
|
const transactionExportSheetName = "Transaksi"
|
|
|
|
func exportTransactionListExcel(c *fiber.Ctx, payments []entity.Payment) error {
|
|
content, err := buildTransactionExportWorkbook(payments)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to generate excel file")
|
|
}
|
|
|
|
filename := fmt.Sprintf("transaksi_%s.xlsx", time.Now().Format("20060102_150405"))
|
|
c.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
|
|
return c.Status(fiber.StatusOK).Send(content)
|
|
}
|
|
|
|
func buildTransactionExportWorkbook(payments []entity.Payment) ([]byte, error) {
|
|
file := excelize.NewFile()
|
|
defer file.Close()
|
|
|
|
defaultSheet := file.GetSheetName(file.GetActiveSheetIndex())
|
|
if defaultSheet != transactionExportSheetName {
|
|
if err := file.SetSheetName(defaultSheet, transactionExportSheetName); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if err := setTransactionExportColumns(file); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := setTransactionExportHeaders(file); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := setTransactionExportRows(file, payments); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := file.SetPanes(transactionExportSheetName, &excelize.Panes{
|
|
Freeze: true,
|
|
YSplit: 1,
|
|
TopLeftCell: "A2",
|
|
ActivePane: "bottomLeft",
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
buffer, err := file.WriteToBuffer()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buffer.Bytes(), nil
|
|
}
|
|
|
|
func setTransactionExportColumns(file *excelize.File) error {
|
|
columnWidths := map[string]float64{
|
|
"A": 20,
|
|
"B": 22,
|
|
"C": 18,
|
|
"D": 25,
|
|
"E": 14,
|
|
"F": 16,
|
|
"G": 16,
|
|
"H": 22,
|
|
"I": 22,
|
|
"J": 18,
|
|
"K": 18,
|
|
"L": 18,
|
|
"M": 30,
|
|
"N": 22,
|
|
"O": 20,
|
|
}
|
|
|
|
sheet := transactionExportSheetName
|
|
for col, width := range columnWidths {
|
|
if err := file.SetColWidth(sheet, col, col, width); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return file.SetRowHeight(sheet, 1, 24)
|
|
}
|
|
|
|
func setTransactionExportHeaders(file *excelize.File) error {
|
|
sheet := transactionExportSheetName
|
|
headers := []string{
|
|
"Kode Pembayaran",
|
|
"No. Referensi",
|
|
"Tipe Transaksi",
|
|
"Pihak",
|
|
"Tipe Pihak",
|
|
"Tanggal Bayar",
|
|
"Metode Bayar",
|
|
"Bank",
|
|
"No. Rekening Bank",
|
|
"Pemasukan",
|
|
"Pengeluaran",
|
|
"Nominal",
|
|
"Catatan",
|
|
"Dibuat Oleh",
|
|
"Status",
|
|
}
|
|
|
|
for i, header := range headers {
|
|
colName, err := excelize.ColumnNumberToName(i + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := file.SetCellValue(sheet, colName+"1", header); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
headerStyle, err := file.NewStyle(&excelize.Style{
|
|
Font: &excelize.Font{Bold: true, Color: "1F2937"},
|
|
Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{"DCEBFA"}},
|
|
Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
|
|
Border: []excelize.Border{
|
|
{Type: "left", Color: "D1D5DB", Style: 1},
|
|
{Type: "top", Color: "D1D5DB", Style: 1},
|
|
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
|
{Type: "right", Color: "D1D5DB", Style: 1},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return file.SetCellStyle(sheet, "A1", "O1", headerStyle)
|
|
}
|
|
|
|
func setTransactionExportRows(file *excelize.File, payments []entity.Payment) error {
|
|
if len(payments) == 0 {
|
|
return nil
|
|
}
|
|
|
|
sheet := transactionExportSheetName
|
|
for i, p := range payments {
|
|
row := strconv.Itoa(i + 2)
|
|
if err := writeTransactionExportRow(file, sheet, row, p); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
lastRow := strconv.Itoa(len(payments) + 1)
|
|
|
|
dataStyle, err := file.NewStyle(&excelize.Style{
|
|
Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center", WrapText: true},
|
|
Border: []excelize.Border{
|
|
{Type: "left", Color: "D1D5DB", Style: 1},
|
|
{Type: "top", Color: "D1D5DB", Style: 1},
|
|
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
|
{Type: "right", Color: "D1D5DB", Style: 1},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := file.SetCellStyle(sheet, "A2", "O"+lastRow, dataStyle); err != nil {
|
|
return err
|
|
}
|
|
|
|
numericStyle, err := file.NewStyle(&excelize.Style{
|
|
Alignment: &excelize.Alignment{Horizontal: "right", Vertical: "center"},
|
|
Border: []excelize.Border{
|
|
{Type: "left", Color: "D1D5DB", Style: 1},
|
|
{Type: "top", Color: "D1D5DB", Style: 1},
|
|
{Type: "bottom", Color: "D1D5DB", Style: 1},
|
|
{Type: "right", Color: "D1D5DB", Style: 1},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return file.SetCellStyle(sheet, "J2", "L"+lastRow, numericStyle)
|
|
}
|
|
|
|
func writeTransactionExportRow(file *excelize.File, sheet, row string, p entity.Payment) error {
|
|
incomeAmount, expenseAmount := txAmounts(p.Direction, p.Nominal)
|
|
|
|
values := []interface{}{
|
|
safeTxText(p.PaymentCode),
|
|
safeTxRefNumber(p.ReferenceNumber),
|
|
safeTxText(txTransactionType(p)),
|
|
safeTxText(txPartyName(p)),
|
|
safeTxText(p.PartyType),
|
|
formatTxDate(p.PaymentDate),
|
|
safeTxText(p.PaymentMethod),
|
|
safeTxBank(p),
|
|
safeTxBankAccount(p),
|
|
incomeAmount,
|
|
expenseAmount,
|
|
p.Nominal,
|
|
safeTxText(p.Notes),
|
|
safeTxText(txCreatedBy(p)),
|
|
formatTxStatus(p),
|
|
}
|
|
|
|
for colIdx, val := range values {
|
|
colName, err := excelize.ColumnNumberToName(colIdx + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := file.SetCellValue(sheet, colName+row, val); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func safeTxText(s string) string {
|
|
trimmed := strings.TrimSpace(s)
|
|
if trimmed == "" {
|
|
return "-"
|
|
}
|
|
return trimmed
|
|
}
|
|
|
|
func safeTxRefNumber(s *string) string {
|
|
if s == nil {
|
|
return "-"
|
|
}
|
|
return safeTxText(*s)
|
|
}
|
|
|
|
func safeTxBank(p entity.Payment) string {
|
|
if p.BankWarehouse.Id == 0 {
|
|
return "-"
|
|
}
|
|
return safeTxText(p.BankWarehouse.Name)
|
|
}
|
|
|
|
func safeTxBankAccount(p entity.Payment) string {
|
|
if p.BankWarehouse.Id == 0 {
|
|
return "-"
|
|
}
|
|
return safeTxText(p.BankWarehouse.AccountNumber)
|
|
}
|
|
|
|
func formatTxDate(t time.Time) string {
|
|
if t.IsZero() {
|
|
return "-"
|
|
}
|
|
loc, err := time.LoadLocation("Asia/Jakarta")
|
|
if err == nil {
|
|
t = t.In(loc)
|
|
}
|
|
return t.Format("02-01-2006")
|
|
}
|
|
|
|
func formatTxStatus(p entity.Payment) string {
|
|
if p.LatestApproval == nil {
|
|
return "-"
|
|
}
|
|
return safeTxText(p.LatestApproval.StepName)
|
|
}
|
|
|
|
func txTransactionType(p entity.Payment) string {
|
|
if p.TransactionType != "" {
|
|
return p.TransactionType
|
|
}
|
|
return p.Direction
|
|
}
|
|
|
|
func txPartyName(p entity.Payment) string {
|
|
switch p.PartyType {
|
|
case "CUSTOMER":
|
|
if p.Customer != nil && p.Customer.Id != 0 {
|
|
return p.Customer.Name
|
|
}
|
|
case "SUPPLIER":
|
|
if p.Supplier != nil && p.Supplier.Id != 0 {
|
|
return p.Supplier.Name
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func txCreatedBy(p entity.Payment) string {
|
|
if p.CreatedUser.Id == 0 {
|
|
return ""
|
|
}
|
|
return p.CreatedUser.Name
|
|
}
|
|
|
|
func txAmounts(direction string, nominal float64) (income, expense float64) {
|
|
switch strings.ToUpper(direction) {
|
|
case "IN":
|
|
return nominal, 0
|
|
case "OUT":
|
|
return 0, nominal
|
|
default:
|
|
return 0, 0
|
|
}
|
|
}
|