mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix(FE): adding color to negative value excel and change select UI
This commit is contained in:
Generated
+4
-20
@@ -4463,7 +4463,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -4474,7 +4473,6 @@
|
|||||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@@ -4547,7 +4545,6 @@
|
|||||||
"integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==",
|
"integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.46.2",
|
"@typescript-eslint/scope-manager": "8.46.2",
|
||||||
"@typescript-eslint/types": "8.46.2",
|
"@typescript-eslint/types": "8.46.2",
|
||||||
@@ -5071,7 +5068,6 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -6002,8 +5998,7 @@
|
|||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/d3-array": {
|
"node_modules/d3-array": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
@@ -6430,8 +6425,7 @@
|
|||||||
"version": "8.6.0",
|
"version": "8.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
||||||
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
|
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/embla-carousel-react": {
|
"node_modules/embla-carousel-react": {
|
||||||
"version": "8.6.0",
|
"version": "8.6.0",
|
||||||
@@ -6701,7 +6695,6 @@
|
|||||||
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -6875,7 +6868,6 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -8508,7 +8500,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.4.tgz",
|
||||||
"integrity": "sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==",
|
"integrity": "sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.28.4",
|
"@babel/runtime": "^7.28.4",
|
||||||
"fast-png": "^6.2.0",
|
"fast-png": "^6.2.0",
|
||||||
@@ -9961,7 +9952,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -9992,7 +9982,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -10060,8 +10049,7 @@
|
|||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/react-number-format": {
|
"node_modules/react-number-format": {
|
||||||
"version": "5.4.4",
|
"version": "5.4.4",
|
||||||
@@ -10078,7 +10066,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/use-sync-external-store": "^0.0.6",
|
"@types/use-sync-external-store": "^0.0.6",
|
||||||
"use-sync-external-store": "^1.4.0"
|
"use-sync-external-store": "^1.4.0"
|
||||||
@@ -10291,8 +10278,7 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/redux-thunk": {
|
"node_modules/redux-thunk": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
@@ -11205,7 +11191,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -11391,7 +11376,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
OptionProps,
|
||||||
|
GroupBase,
|
||||||
|
components as ReactSelectComponents,
|
||||||
|
} from 'react-select';
|
||||||
|
import SelectInput, { OptionType, SelectInputProps } from './SelectInput';
|
||||||
|
import { cn } from '@/lib/helper';
|
||||||
|
|
||||||
|
interface SelectInputRadioProps<T = OptionType>
|
||||||
|
extends Omit<SelectInputProps<T>, 'closeMenuOnSelect' | 'optionComponent'> {
|
||||||
|
closeMenuOnSelect?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RadioOption = <
|
||||||
|
T extends OptionType,
|
||||||
|
IsMulti extends boolean,
|
||||||
|
Group extends GroupBase<T>,
|
||||||
|
>(
|
||||||
|
props: OptionProps<T, IsMulti, Group>
|
||||||
|
) => {
|
||||||
|
const { isSelected, label, innerRef, innerProps, className } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={innerRef}
|
||||||
|
{...innerProps}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-2 px-3 py-2 cursor-pointer',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() => null}
|
||||||
|
className='radio radio-sm radio-primary pointer-events-none'
|
||||||
|
/>
|
||||||
|
<label className='cursor-pointer flex-1 select-none'>{label}</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SelectInputRadio = <T extends OptionType>(
|
||||||
|
props: SelectInputRadioProps<T>
|
||||||
|
) => {
|
||||||
|
const { closeMenuOnSelect = true, className, ...restProps } = props;
|
||||||
|
|
||||||
|
const customComponents = useMemo(() => {
|
||||||
|
return {
|
||||||
|
Option: RadioOption as typeof ReactSelectComponents.Option,
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SelectInput<T>
|
||||||
|
{...restProps}
|
||||||
|
closeMenuOnSelect={closeMenuOnSelect}
|
||||||
|
className={{
|
||||||
|
...className,
|
||||||
|
select: cn(className?.select, 'select-radio'),
|
||||||
|
}}
|
||||||
|
components={customComponents}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectInputRadio;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import * as XLSX from 'xlsx';
|
import ExcelJS from 'exceljs';
|
||||||
import { formatDate } from '@/lib/helper';
|
import { formatDate } from '@/lib/helper';
|
||||||
import { DebtRow, DebtSupplier } from '@/types/api/report/debt-supplier';
|
import { DebtRow, DebtSupplier } from '@/types/api/report/debt-supplier';
|
||||||
|
|
||||||
@@ -8,115 +8,174 @@ interface DebtSupplierExportExcelParams {
|
|||||||
data: DebtSupplier[];
|
data: DebtSupplier[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateDebtSupplierExcel = (
|
export const generateDebtSupplierExcel = async (
|
||||||
params: DebtSupplierExportExcelParams
|
params: DebtSupplierExportExcelParams
|
||||||
): void => {
|
): Promise<void> => {
|
||||||
if (!params.data || params.data.length === 0) {
|
if (!params.data || params.data.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workbook = XLSX.utils.book_new();
|
const workbook = new ExcelJS.Workbook();
|
||||||
|
|
||||||
params.data.forEach((supplierReport) => {
|
const columns = [
|
||||||
|
{ header: 'No', key: 'no', width: 5 },
|
||||||
|
{ header: 'Nomor PR', key: 'prNumber', width: 14 },
|
||||||
|
{ header: 'Nomor PO', key: 'poNumber', width: 14 },
|
||||||
|
{ header: 'Tanggal Terima/Bayar', key: 'receivedDate', width: 20 },
|
||||||
|
{ header: 'Tanggal PO', key: 'poDate', width: 10 },
|
||||||
|
{ header: 'Aging (Hari)', key: 'aging', width: 10 },
|
||||||
|
{ header: 'Area', key: 'area', width: 15 },
|
||||||
|
{ header: 'Gudang', key: 'warehouse', width: 15 },
|
||||||
|
{ header: 'Jatuh Tempo', key: 'dueDate', width: 12 },
|
||||||
|
{ header: 'Status Jatuh Tempo', key: 'dueStatus', width: 20 },
|
||||||
|
{ header: 'Nominal Pembelian (Rp)', key: 'totalPrice', width: 20 },
|
||||||
|
{ header: 'Pembayaran (Rp)', key: 'paymentPrice', width: 15 },
|
||||||
|
{ header: 'Sisa Saldo Hutang (Rp)', key: 'balance', width: 20 },
|
||||||
|
{ header: 'Status', key: 'status', width: 12 },
|
||||||
|
{ header: 'Nomor Perjalanan', key: 'travelNumber', width: 15 },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const supplierReport of params.data) {
|
||||||
const supplierData = supplierReport.rows;
|
const supplierData = supplierReport.rows;
|
||||||
const supplierName = supplierReport.supplier.name || 'Unknown Supplier';
|
const supplierName = supplierReport.supplier.name || 'Unknown Supplier';
|
||||||
|
|
||||||
const excelData: { [key: string]: string | number }[] = [
|
const worksheet = workbook.addWorksheet(supplierName.substring(0, 31));
|
||||||
{
|
worksheet.columns = columns;
|
||||||
No: '',
|
|
||||||
'Nomor PR': '',
|
// Add initial balance row
|
||||||
'Nomor PO': '',
|
const initialRow = worksheet.addRow({
|
||||||
'Tanggal Terima/Bayar': '',
|
no: '',
|
||||||
'Tanggal PO': '',
|
prNumber: '',
|
||||||
'Aging (Hari)': '',
|
poNumber: '',
|
||||||
Area: '',
|
receivedDate: '',
|
||||||
Gudang: '',
|
poDate: '',
|
||||||
'Jatuh Tempo': '',
|
aging: '',
|
||||||
'Status Jatuh Tempo': '',
|
area: '',
|
||||||
'Nominal Pembelian (Rp)': '',
|
warehouse: '',
|
||||||
'Pembayaran (Rp)': '',
|
dueDate: '',
|
||||||
'Sisa Saldo Hutang (Rp)': supplierReport.initial_balance || 0,
|
dueStatus: '',
|
||||||
Status: '',
|
totalPrice: '',
|
||||||
'Nomor Perjalanan': '',
|
paymentPrice: '',
|
||||||
},
|
balance: supplierReport.initial_balance || 0,
|
||||||
...supplierData.map((item, index) => ({
|
status: '',
|
||||||
No: index + 1,
|
travelNumber: '',
|
||||||
'Nomor PR': item.pr_number || '',
|
});
|
||||||
'Nomor PO': item.po_number || '',
|
|
||||||
'Tanggal Terima/Bayar': item.received_date
|
// Apply red color if initial balance is negative
|
||||||
|
const initialBalanceCell = initialRow.getCell('balance');
|
||||||
|
if (
|
||||||
|
typeof supplierReport.initial_balance === 'number' &&
|
||||||
|
supplierReport.initial_balance < 0
|
||||||
|
) {
|
||||||
|
initialBalanceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add data rows
|
||||||
|
supplierData.forEach((item, index) => {
|
||||||
|
const row = worksheet.addRow({
|
||||||
|
no: index + 1,
|
||||||
|
prNumber: item.pr_number || '',
|
||||||
|
poNumber: item.po_number || '',
|
||||||
|
receivedDate: item.received_date
|
||||||
? item.received_date != '-'
|
? item.received_date != '-'
|
||||||
? formatDate(item.received_date, 'MM/DD/YYYY')
|
? formatDate(item.received_date, 'MM/DD/YYYY')
|
||||||
: '-'
|
: '-'
|
||||||
: '-',
|
: '-',
|
||||||
'Tanggal PO': item.po_date
|
poDate: item.po_date
|
||||||
? item.po_date != '-'
|
? item.po_date != '-'
|
||||||
? formatDate(item.po_date, 'MM/DD/YYYY')
|
? formatDate(item.po_date, 'MM/DD/YYYY')
|
||||||
: '-'
|
: '-'
|
||||||
: '-',
|
: '-',
|
||||||
'Aging (Hari)': item.aging || 0,
|
aging: item.aging || 0,
|
||||||
Area: item.area?.name || '',
|
area: item.area?.name || '',
|
||||||
Gudang: item.warehouse?.name || '',
|
warehouse: item.warehouse?.name || '',
|
||||||
'Jatuh Tempo': item.due_date
|
dueDate: item.due_date
|
||||||
? item.due_date != '-'
|
? item.due_date != '-'
|
||||||
? formatDate(item.due_date, 'MM/DD/YYYY')
|
? formatDate(item.due_date, 'MM/DD/YYYY')
|
||||||
: '-'
|
: '-'
|
||||||
: '-',
|
: '-',
|
||||||
'Status Jatuh Tempo': item.due_status || '',
|
dueStatus: item.due_status || '',
|
||||||
'Nominal Pembelian (Rp)': item.total_price || 0,
|
totalPrice: item.total_price || 0,
|
||||||
'Pembayaran (Rp)': item.payment_price || 0,
|
paymentPrice: item.payment_price || 0,
|
||||||
'Sisa Saldo Hutang (Rp)': item.balance || 0,
|
balance: item.balance || 0,
|
||||||
Status: item.status || '',
|
status: item.status || '',
|
||||||
'Nomor Perjalanan': item.travel_number || '',
|
travelNumber: item.travel_number || '',
|
||||||
})),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (supplierReport.total) {
|
|
||||||
excelData.push({
|
|
||||||
No: 'Total',
|
|
||||||
'Nomor PR': '',
|
|
||||||
'Nomor PO': '',
|
|
||||||
'Tanggal Terima/Bayar': '',
|
|
||||||
'Tanggal PO': '',
|
|
||||||
'Aging (Hari)': supplierReport.total.aging || 0,
|
|
||||||
Area: '',
|
|
||||||
Gudang: '',
|
|
||||||
'Jatuh Tempo': '',
|
|
||||||
'Status Jatuh Tempo': '',
|
|
||||||
'Nominal Pembelian (Rp)': supplierReport.total.total_price || 0,
|
|
||||||
'Pembayaran (Rp)': supplierReport.total.payment_price || 0,
|
|
||||||
'Sisa Saldo Hutang (Rp)': supplierReport.total.debt_price || 0,
|
|
||||||
Status: '',
|
|
||||||
'Nomor Perjalanan': '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Apply red color for negative values
|
||||||
|
const totalPriceCell = row.getCell('totalPrice');
|
||||||
|
if (typeof item.total_price === 'number' && item.total_price < 0) {
|
||||||
|
totalPriceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
}
|
}
|
||||||
|
|
||||||
const worksheet = XLSX.utils.json_to_sheet(excelData);
|
const paymentPriceCell = row.getCell('paymentPrice');
|
||||||
|
if (typeof item.payment_price === 'number' && item.payment_price < 0) {
|
||||||
|
paymentPriceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
|
}
|
||||||
|
|
||||||
const colWidths = [
|
const balanceCell = row.getCell('balance');
|
||||||
{ wch: 5 }, // No
|
if (typeof item.balance === 'number' && item.balance < 0) {
|
||||||
{ wch: 10 }, // Nomor PR
|
balanceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
{ wch: 10 }, // Nomor PO
|
}
|
||||||
{ wch: 20 }, // Tanggal Terima/Bayar
|
|
||||||
{ wch: 10 }, // Tanggal PO
|
|
||||||
{ wch: 10 }, // Aging
|
|
||||||
{ wch: 15 }, // Area
|
|
||||||
{ wch: 15 }, // Gudang
|
|
||||||
{ wch: 12 }, // Jatuh Tempo
|
|
||||||
{ wch: 20 }, // Status Jatuh Tempo
|
|
||||||
{ wch: 20 }, // Nominal Pembelian (Rp)
|
|
||||||
{ wch: 15 }, // Pembayaran (Rp)
|
|
||||||
{ wch: 20 }, // Sisa Saldo Hutang (Rp)
|
|
||||||
{ wch: 12 }, // Status
|
|
||||||
{ wch: 15 }, // Nomor Perjalanan
|
|
||||||
];
|
|
||||||
worksheet['!cols'] = colWidths;
|
|
||||||
|
|
||||||
const sheetName =
|
|
||||||
supplierName.length > 31 ? supplierName.substring(0, 31) : supplierName;
|
|
||||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add total row
|
||||||
|
if (supplierReport.total) {
|
||||||
|
const totalRow = worksheet.addRow({
|
||||||
|
no: 'Total',
|
||||||
|
prNumber: '',
|
||||||
|
poNumber: '',
|
||||||
|
receivedDate: '',
|
||||||
|
poDate: '',
|
||||||
|
aging: supplierReport.total.aging || 0,
|
||||||
|
area: '',
|
||||||
|
warehouse: '',
|
||||||
|
dueDate: '',
|
||||||
|
dueStatus: '',
|
||||||
|
totalPrice: supplierReport.total.total_price || 0,
|
||||||
|
paymentPrice: supplierReport.total.payment_price || 0,
|
||||||
|
balance: supplierReport.total.debt_price || 0,
|
||||||
|
status: '',
|
||||||
|
travelNumber: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Apply red color for negative totals
|
||||||
|
const totalPriceCell = totalRow.getCell('totalPrice');
|
||||||
|
if (
|
||||||
|
typeof supplierReport.total.total_price === 'number' &&
|
||||||
|
supplierReport.total.total_price < 0
|
||||||
|
) {
|
||||||
|
totalPriceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
|
}
|
||||||
|
|
||||||
|
const paymentPriceCell = totalRow.getCell('paymentPrice');
|
||||||
|
if (
|
||||||
|
typeof supplierReport.total.payment_price === 'number' &&
|
||||||
|
supplierReport.total.payment_price < 0
|
||||||
|
) {
|
||||||
|
paymentPriceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
|
}
|
||||||
|
|
||||||
|
const balanceCell = totalRow.getCell('balance');
|
||||||
|
if (
|
||||||
|
typeof supplierReport.total.debt_price === 'number' &&
|
||||||
|
supplierReport.total.debt_price < 0
|
||||||
|
) {
|
||||||
|
balanceCell.font = { color: { argb: 'FFFF0000' } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const filename = `laporan-hutang-supplier-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.xlsx`;
|
const filename = `laporan-hutang-supplier-${formatDate(new Date(), 'YYYY-MM-DD-HHmm')}.xlsx`;
|
||||||
|
|
||||||
XLSX.writeFile(workbook, filename);
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
|
const blob = new Blob([buffer], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
});
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import ButtonFilter from '@/components/helper/ButtonFilter';
|
|||||||
import Badge from '@/components/Badge';
|
import Badge from '@/components/Badge';
|
||||||
import { Color } from '@/types/theme';
|
import { Color } from '@/types/theme';
|
||||||
import { Supplier } from '@/types/api/master-data/supplier';
|
import { Supplier } from '@/types/api/master-data/supplier';
|
||||||
|
import SelectInputCheckbox from '@/components/input/SelectInputCheckbox';
|
||||||
|
import SelectInputRadio from '@/components/input/SelectInputRadio';
|
||||||
|
|
||||||
const dueStatus: Record<string, Color> = {
|
const dueStatus: Record<string, Color> = {
|
||||||
'Sudah Jatuh Tempo': 'error',
|
'Sudah Jatuh Tempo': 'error',
|
||||||
@@ -671,7 +673,7 @@ const DebtSupplierTab = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<SelectInput
|
<SelectInputCheckbox
|
||||||
label='Supplier'
|
label='Supplier'
|
||||||
placeholder='Pilih Supplier'
|
placeholder='Pilih Supplier'
|
||||||
isMulti
|
isMulti
|
||||||
@@ -696,7 +698,7 @@ const DebtSupplierTab = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<SelectInput
|
<SelectInputRadio
|
||||||
label='Filter Berdasarkan'
|
label='Filter Berdasarkan'
|
||||||
placeholder='Pilih Filter Berdasarkan'
|
placeholder='Pilih Filter Berdasarkan'
|
||||||
options={dataTypeOptions}
|
options={dataTypeOptions}
|
||||||
|
|||||||
Reference in New Issue
Block a user