diff --git a/src/i18n/eng.ts b/src/i18n/eng.ts index 5d6cb988..c3831765 100644 --- a/src/i18n/eng.ts +++ b/src/i18n/eng.ts @@ -149,6 +149,7 @@ export default { included: 'Included', notIncluded: 'Not Included', dueDate: 'Due date', + year: 'year', }, menu: { @@ -1358,6 +1359,7 @@ export default { Invoice: 'Payment Report', Product: 'Product and Service Report', Sale: 'Sales Summary Report', + Profit: 'Profit and Loss Report', }, document: { code: 'Code', @@ -1384,6 +1386,15 @@ export default { name: 'Name', count: 'Sold Quantity', }, + profit: { + byMonth: 'Profit Table by Month', + byYear: 'Profit Table by Year', + month: 'Month', + year: 'Year (AD)', + netProfit: 'Net Profit', + expenses: 'Expenses', + income: 'Income', + }, }, dashboard: { title: 'Dashboard', @@ -1417,4 +1428,19 @@ export default { caption: 'Based on Tax Invoices', }, }, + + month: { + 1: 'January', + 2: 'February', + 3: 'March', + 4: 'April', + 5: 'May', + 6: 'June', + 7: 'July', + 8: 'August', + 9: 'September', + 10: 'October', + 11: 'November', + 12: 'December', + }, }; diff --git a/src/i18n/tha.ts b/src/i18n/tha.ts index 8d3611f5..cbf1b422 100644 --- a/src/i18n/tha.ts +++ b/src/i18n/tha.ts @@ -149,6 +149,7 @@ export default { included: 'รวม', notIncluded: 'ไม่รวม', dueDate: 'วันครบกำหนด', + year: 'ปี', }, menu: { @@ -1338,6 +1339,7 @@ export default { Invoice: 'รายงานการชำระเงิน', Product: 'รายงานสินค้าและบริการ', Sale: 'รายงานสรุปยอดขาย', + Profit: 'รายงานกำไรและขาดทุน', }, document: { code: 'รหัส', @@ -1365,6 +1367,15 @@ export default { name: 'ชื่อ', count: 'จำนวนที่ขาย', }, + profit: { + byMonth: 'ตารางผลกำไรตามเดือน', + byYear: 'ตารางผลกำไรตามปี', + month: 'เดือน', + year: 'ปี (ค.ศ.)', + netProfit: 'กำไร', + expenses: 'ต้นทุน', + income: 'รายได้', + }, }, dashboard: { title: 'Dashboard', @@ -1398,4 +1409,19 @@ export default { caption: 'ตามใบกำกับภาษี', }, }, + + month: { + 1: 'มกราคม', + 2: 'กุมภาพันธ์', + 3: 'มีนาคม', + 4: 'เมษายน', + 5: 'พฤษภาคม', + 6: 'มิถุนายน', + 7: 'กรกฎาคม', + 8: 'สิงหาคม', + 9: 'กันยายน', + 10: 'ตุลาคม', + 11: 'พฤศจิกายน', + 12: 'ธันวาคม', + }, }; diff --git a/src/pages/14_report/MainPage.vue b/src/pages/14_report/MainPage.vue index cdd287d2..2ee6b411 100644 --- a/src/pages/14_report/MainPage.vue +++ b/src/pages/14_report/MainPage.vue @@ -1,6 +1,6 @@ + + diff --git a/src/pages/14_report/Table/TableReport.vue b/src/pages/14_report/Table/TableReport.vue index b7671eaa..53377433 100644 --- a/src/pages/14_report/Table/TableReport.vue +++ b/src/pages/14_report/Table/TableReport.vue @@ -5,6 +5,8 @@ const prop = withDefaults( defineProps<{ row: QTableProps['rows']; columns: QTableProps['columns']; + hideHeader?: boolean; + hideBottom?: boolean; }>(), { row: () => [], @@ -22,6 +24,8 @@ const prop = withDefaults( })) " :columns + :hideHeader + :hideBottom bordered flat selection="multiple" diff --git a/src/pages/14_report/constants.ts b/src/pages/14_report/constants.ts index 6a37b9f5..2ff3a22c 100644 --- a/src/pages/14_report/constants.ts +++ b/src/pages/14_report/constants.ts @@ -14,6 +14,7 @@ export enum ViewMode { Receipt = 'receipt', Product = 'product', Sale = 'sale', + Profit = 'profit', } type ColumnsSale = { @@ -28,6 +29,25 @@ type ColumnsBySale = ColumnsSale & { gender?: string; }; +type ColumnsProfix = { + title: string; + amount: number; +}; + +type ColumnsProfixByMonth = { + month: string; + netProfit: number; + expenses: number; + income: number; +}; + +type ColumnsProfixByYear = Omit & { + year: string; + netProfit: number; + expenses: number; + income: number; +}; + export const colReportQuotation = [ { name: 'code', @@ -169,9 +189,81 @@ export const colReportBySale = [ }, ] as const satisfies QTableProps['columns']; +export const colProfit = [ + { + name: 'title', + align: 'left', + label: '', + field: (data: ColumnsProfix) => data.title, + }, + { + name: 'amount', + align: 'left', + label: '', + field: (data: ColumnsProfix) => formatNumberDecimal(data.amount, 2), + }, +] as const satisfies QTableProps['columns']; + +export const colProfitByMoth = [ + { + name: '#title', + align: 'left', + label: 'report.profit.month', + field: '', + }, + { + name: 'netProfit', + align: 'left', + label: 'report.profit.netProfit', + field: (data: ColumnsProfixByMonth) => + formatNumberDecimal(data.netProfit, 2), + }, + { + name: 'expenses', + align: 'left', + label: 'report.profit.expenses', + field: (data: ColumnsProfixByMonth) => + formatNumberDecimal(data.expenses, 2), + }, + { + name: 'income', + align: 'left', + label: 'report.profit.income', + field: (data: ColumnsProfixByMonth) => formatNumberDecimal(data.income, 2), + }, +] as const satisfies QTableProps['columns']; + +export const colProfitByYear = [ + { + name: 'title', + align: 'left', + label: 'report.profit.year', + field: (data: ColumnsProfixByYear) => data.year, + }, + { + name: 'netProfit', + align: 'left', + label: 'report.profit.netProfit', + field: (data: ColumnsProfixByYear) => + formatNumberDecimal(data.netProfit, 2), + }, + { + name: 'expenses', + align: 'left', + label: 'report.profit.expenses', + field: (data: ColumnsProfixByYear) => formatNumberDecimal(data.expenses, 2), + }, + { + name: 'income', + align: 'left', + label: 'report.profit.income', + field: (data: ColumnsProfixByYear) => formatNumberDecimal(data.income, 2), + }, +] as const satisfies QTableProps['columns']; export const pageTabs = [ { label: 'Document', value: ViewMode.Document, by: ['user'] }, { label: 'Invoice', value: ViewMode.Invoice, by: ['user'] }, { label: 'Product', value: ViewMode.Product, by: ['user'] }, { label: 'Sale', value: ViewMode.Sale, by: ['admin'] }, + { label: 'Profit', value: ViewMode.Profit, by: ['admin'] }, ]; diff --git a/src/stores/report/index.ts b/src/stores/report/index.ts index 7bddfdf9..f23d62c6 100644 --- a/src/stores/report/index.ts +++ b/src/stores/report/index.ts @@ -7,6 +7,7 @@ import { ReportProduct, ReportQuotation, ReportSale, + ReportProfit, } from './types'; import { baseUrl } from '../utils'; import { getToken } from 'src/services/keycloak'; @@ -120,6 +121,31 @@ export async function getReportPayment(params?: { return null; } +export async function getReportProfit(params?: { + years?: number; + startDate?: string | Date; + endDate?: string | Date; +}) { + let opts = params || {}; + + if (params?.years) { + const currentYear = new Date().getFullYear(); + opts.startDate = new Date(currentYear - params.years, 0, 1); // ✅ 1 ม.ค. ของปีที่ต้องการ + opts.endDate = new Date(currentYear, 11, 31); // ✅ 31 ธ.ค. ของปีปัจจุบัน + } + + const res = await api.get(`/${ENDPOINT}/profit`, { + params: { + startDate: opts.startDate, + endDate: opts.endDate, + }, + }); + if (res.status < 400) { + return res.data; + } + return null; +} + export const useReportStore = defineStore('report-store', () => { const dataReportQuotation = ref([]); const dataReportInvoice = ref([]); @@ -127,6 +153,7 @@ export const useReportStore = defineStore('report-store', () => { const dataReportSale = ref(); const dataReportProduct = ref([]); const dataReportPayment = ref([]); + const dataReportProfit = ref(); return { dataReportQuotation, @@ -135,6 +162,7 @@ export const useReportStore = defineStore('report-store', () => { dataReportSale, dataReportProduct, dataReportPayment, + dataReportProfit, downloadReportQuotation, getReportQuotation, @@ -147,5 +175,6 @@ export const useReportStore = defineStore('report-store', () => { downloadReportProduct, getReportProduct, getReportPayment, + getReportProfit, }; }); diff --git a/src/stores/report/types.ts b/src/stores/report/types.ts index ab46b212..522c9ce3 100644 --- a/src/stores/report/types.ts +++ b/src/stores/report/types.ts @@ -50,3 +50,16 @@ export type ReportSale = { bySale: (User & { _count: number })[]; byProductGroup: (Omit & { _count: number })[]; }; + +export type ReportProfit = { + dataset: { + netProfit: number; + expenses: number; + income: number; + year: number; + month: number; + }[]; + netProfit: number; + expenses: number; + income: number; +};