From 121d992b686c68c540f211a6d89e96c0c93cc569 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 2 Nov 2023 22:57:41 +0200 Subject: [PATCH 01/10] chore: updating CONTRIBUTING.md --- CONTRIBUTING.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aa9093c25..af05add32 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,8 @@ Contributions via pull requests are much appreciated. Once the approach is agree --- ## Local Setup Prerequisites - - The application currently supports **Node.js v14.x**. Please ensure that you are using this version of Node.js when developing. (use [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) to switch between node versions) + - The application currently supports **Node.js v18.x**. + - `pnpm` packages manager, (from pnpm [guide](https://pnpm.io/installation) pick any installation method). ## Contribute to Backend @@ -44,11 +45,10 @@ Contributions via pull requests are much appreciated. Once the approach is agree cp .env.example .env ``` -- Install all npm dependencies of the monorepo, you don't have to change directory to the `backend` package. just hit these command on root directory and it will install dependencies of all packages. +- Install all npm dependencies of the monorepo, you don't have to change directory to the `backend` package. just hit the command on root directory and it will install dependencies of all packages. ``` -npm install -npm run bootstrap +pnpm install ``` - Run all required docker containers in the development, we already configured all containers under `docker-compose.yml`. @@ -69,7 +69,7 @@ cefa73fe2881 bigcapital-redis "docker-entrypoint.s…" 7 seconds ago Up - There're some CLI commands we should run before running the server like databaase migration, so we need to build the `server` app first. ``` -npm run build:server +pnpm run build:server ``` - Run the database migration for system database. @@ -87,7 +87,7 @@ Batch 1 run: 6 migrations - Next, start the webapp application. ``` -npm run dev:server +pnpm run dev:server ``` **[`^top^`](#)** @@ -105,14 +105,13 @@ git clone https://github.com/bigcapital/bigcapital.git && cd bigcaptial - Install all npm dependencies of the monorepo, you don't have to change directory to the `frontend` package. just hit that command and will install all packages across all application. ``` -npm install -npm run bootstrap +pnpm install ``` - Next, start the webapp application. ``` -npm run dev:webapp +pnpm run dev:webapp ``` **[`^top^`](#)** From a3d9e8ef2b0bed2eb7f3a3d78fea85095b909f12 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sat, 4 Nov 2023 15:32:50 +0200 Subject: [PATCH 02/10] chore: configure gitpod --- .gitpod.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000..837842f32 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,15 @@ +tasks: + - name: Init + init: pnpm install && docker-compose pull + command: cp .env.example .env && docker-compose up -d && pnpm run dev + +ports: + - port: 4000 + visibility: public + onOpen: open-browser + - port: 3000 + visibility: public + onOpen: ignore + - port: 3306 + visibility: public + onOpen: ignore \ No newline at end of file From eeb67d4005affeeca622c5bef51e1fdcb7589592 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 5 Nov 2023 02:22:26 +0200 Subject: [PATCH 03/10] chore: configure Gitpod --- .gitpod.yml | 13 ++++++++++--- packages/webapp/craco.config.js | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 837842f32..af63be869 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,12 +1,19 @@ tasks: - name: Init - init: pnpm install && docker-compose pull - command: cp .env.example .env && docker-compose up -d && pnpm run dev + init: | + pnpm install && + docker-compose pull && + cp .env.example .env && + pnpm run build:server && + node packages/server/build/commands.js system:migrate:latest + command: | + docker-compose up -d && + pnpm run dev ports: - port: 4000 visibility: public - onOpen: open-browser + onOpen: open-preview - port: 3000 visibility: public onOpen: ignore diff --git a/packages/webapp/craco.config.js b/packages/webapp/craco.config.js index c86d33ebc..4d444d065 100644 --- a/packages/webapp/craco.config.js +++ b/packages/webapp/craco.config.js @@ -11,4 +11,7 @@ module.exports = { }, }, }, + devServer: { + allowedHosts: process.env.GITPOD_HOST ? 'all' : 'auto' + }, }; From 5027f9fe5d725cbe649ea187388a4d146a5f07f0 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 5 Nov 2023 02:58:48 +0200 Subject: [PATCH 04/10] chore: configure Gitpod --- .env.example | 2 +- .gitpod.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index f07f28c5f..c3dc23d8f 100644 --- a/.env.example +++ b/.env.example @@ -8,7 +8,7 @@ MAIL_FROM_NAME= MAIL_FROM_ADDRESS= # Database -DB_HOST=mysql +DB_HOST=localhost DB_USER=bigcapital DB_PASSWORD=bigcapital DB_ROOT_PASSWORD=root diff --git a/.gitpod.yml b/.gitpod.yml index af63be869..9aea12456 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -2,8 +2,8 @@ tasks: - name: Init init: | pnpm install && - docker-compose pull && cp .env.example .env && + docker-compose up -d && pnpm run build:server && node packages/server/build/commands.js system:migrate:latest command: | From a2cbab0bc396a252b4b3beeb806010c8dfe32d1f Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 5 Nov 2023 03:28:04 +0200 Subject: [PATCH 05/10] chore: update README.md to add Gitpod --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index 9db2572d6..5476c3201 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,31 @@ Bigcapital is a smart and open-source accounting and inventory software, Bigcapi

+# Getting Started + +We've got serveral options on dev and prod depending on your need to get started quickly with Bigcapital. + +## Self-hosted + +Bigcapital is available open-source under AGPL license. You can host it on your own servers using Docker. + +### Docker + +To get started with self-hosted with Docker and Docker Compose, take a look at the [Docker guide](https://docs.bigcapital.ly/deployment/docker). + +## Development + +### Local Setup + +To get started locally, we have a [guide to help you](https://github.com/bigcapitalhq/bigcapital/blob/develop/CONTRIBUTING.md). + +### Gitpod + +- Click the Gitpod button below to open this project in development mode. +- This will open and configure the workspace in your browser with all the necessary dependencies. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/new/#https://github.com/bigcapitalhq/bigcapital) + # Resources - [Documentation](https://docs.bigcapital.ly/) - Learn how to use. From 50164873ce99f5b9c8e0e3b53615c453f678d0fb Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 5 Nov 2023 20:11:27 +0200 Subject: [PATCH 06/10] chore: remove the duplicated keys in lang files --- packages/webapp/src/lang/ar/index.json | 7 ------- packages/webapp/src/lang/en/index.json | 10 +--------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/webapp/src/lang/ar/index.json b/packages/webapp/src/lang/ar/index.json index b2325c53f..976b049d6 100644 --- a/packages/webapp/src/lang/ar/index.json +++ b/packages/webapp/src/lang/ar/index.json @@ -407,7 +407,6 @@ "display_name": "اسم العرض", "the_customer_has_been_created_successfully": "تم إنشاء زبون جديد بنجاح.", "select_contact": "حدد جهة اتصال", - "contact": "جهة اتصال", "contacts": "جهات الاتصال", "close_sidebar": "إغلاق الشريط الجانبي.", "open_sidebar": "فتح الشريط الجانبي.", @@ -804,7 +803,6 @@ "all_customers": "كل الزبائن", "all_vendors": "كل الموردين", "selected_customers": "{عدد} العملاء المحددين", - "transaction_number": " العملية", "running_balance": "الرصيد التحليلي", "view_all": "مشاهدة الكل", "payment_via_voucher": "الدفع عن طريق القسيمة", @@ -871,7 +869,6 @@ "inventory_valuation": "تقييم المخزون", "payable_accounts_should_assign_with_vendors": "يجب تعيين حسابات الدفع مع البائعين.", "account_paper": "ورقة الحساب", - "transaction_date": "تاريخ العملة", "account_normal": "طبيعة الحساب", "published_at": "نشرت في", "customers_balance_summary": "ملخص رصيد الزبائن", @@ -922,7 +919,6 @@ "drag_drop_files_here_or_click_here": "قم بسحب/إسقاط الملفات هنا أو انقر هنا.", "enter_an_item": "أدخل منتج ...", "due_amount": "القيمة المستحقة", - "invoice_details": "تفاصيل الفاتورة", "setting_your_auto_generated_estimate_number": "عيين رقم العرض الذي تم إنشاؤه تلقائيًا", "setting_your_auto_generated_journal_number": "عيين رقم قيد اليدوي الذي تم إنشاؤه تلقائيًا", "setting_your_auto_generated_invoice_number": "عيين رقم الفاتورة الذي تم إنشاؤه تلقائيًا", @@ -934,7 +930,6 @@ "receive_full_amount": "استلام المبلغ كاملاً", "manage_the_organization_s_services_and_products": "إدارة الخدمات والمنتجات للمنشأة.", "here_a_list_of_your_organization_products_and_services": "هنا قائمة بمنتجات وخدمات عملك ، لاستخدامها عند إنشاء فواتير أو فواتير لموردين أو البائعين.", - "receipt_details": "تفاصيل الإيصال", "bill_details": "تفاصيل الفاتورة", "new_bill_payment": "سند مورد جديد", "new_sale_invoice": "فاتورة بيع جديدة", @@ -1148,7 +1143,6 @@ "conditions_and_terms": "Conditions and terms", "allocate_landed_coast": "تحميل تكلفة اضافية", "transaction_date": "تاريخ المعاملة", - "transaction_type": "نوع المعاملة", "transaction_id": "رقم المعاملة", "transaction_number": "رقم المعاملة", "transaction_line": "سطر المعاملة", @@ -1177,7 +1171,6 @@ "contact": "جهة الاتصال", "invoice_details": "تفاصيل الفاتورة", "receipt_details": "تفاصيل الإيصال", - "payment_receive_details": "تفاصيل سند الزبون", "payment_made_details": "تفاصيل سند المورد", "New item category": "اضافة تصنيف صنف جديد", "New service": "اضافة خدمة جديدة", diff --git a/packages/webapp/src/lang/en/index.json b/packages/webapp/src/lang/en/index.json index 4dd764c3f..4a78b4e76 100644 --- a/packages/webapp/src/lang/en/index.json +++ b/packages/webapp/src/lang/en/index.json @@ -408,7 +408,6 @@ "display_name": "Display Name", "the_customer_has_been_created_successfully": "The customer has been created successfully.", "select_contact": "Select contact", - "contact": "Contact", "contacts": "Contacts", "close_sidebar": "Close sidebar.", "open_sidebar": "Open sidebar.", @@ -796,7 +795,6 @@ "all_customers": "All Customers", "all_vendors": "All Vendors", "selected_customers": "{count} Selected Customers", - "transaction_number": "Transaction #", "running_balance": "Running balance", "view_all": "View all", "payment_via_voucher": "Payment via voucher", @@ -867,8 +865,6 @@ "inventory_valuation": "Inventory valuation", "payable_accounts_should_assign_with_vendors": "Payable accounts should assign with vendors.", "account_paper": "Account Paper", - "transaction_date": "Transaction date", - "transaction_type": "Transaction type", "account_normal": "Account normal", "published_at": "Published at", "customers_balance_summary": "Customers Balance Summary", @@ -1130,7 +1126,6 @@ "transaction_date": "Transaction date", "transaction_type": "Transaction type", "transaction_id": "Transaction #", - "transaction_number": "Transaction number", "transaction_line": "Transaction line", "allocation_method": "Allocation method", "other_income_account": "Other income account", @@ -1157,9 +1152,6 @@ "journal_entries": "Journal Entries", "contact": "Contact", "invoice_details": "Invoice details", - "receipt_details": "Receipt details", - "payment_receive_details": "Payment receive details", - "payment_made_details": "Payment made details", "New item category": "New item category", "New service": "New service", "New inventory item": "New inventory item", @@ -2078,7 +2070,7 @@ "project_task.dialog.edit_success_message": "The task has been edited successfully.", "project_task.action.edit_task": "Edit Task", "project_task.action.delete_task": "Delete Task", - "project_task.rate": "{rate} / hour", +"project_task.rate": "{rate} / hour", "project_task.fixed_price": "Fixed price", "project_task.non_chargable": "Non-chargeable", "project_task.estimate_hours": "• {estimate_hours}h 0m estimated", From f0f0045353afdcb3000499630f3fa58d71cde18a Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 7 Nov 2023 14:55:48 +0200 Subject: [PATCH 07/10] chore(server): remove duplicated locales files --- packages/server/src/locales/ar.json | 640 --------------------------- packages/server/src/locales/en.json | 642 ---------------------------- 2 files changed, 1282 deletions(-) delete mode 100644 packages/server/src/locales/ar.json delete mode 100644 packages/server/src/locales/en.json diff --git a/packages/server/src/locales/ar.json b/packages/server/src/locales/ar.json deleted file mode 100644 index a52b13d51..000000000 --- a/packages/server/src/locales/ar.json +++ /dev/null @@ -1,640 +0,0 @@ -{ - "Petty Cash": "العهدة", - "Cash": "النقدية", - "Bank": "المصرف", - "Other Income": "إيرادات اخري", - "Interest Income": "إيرادات الفوائد", - "Depreciation Expense": "مصاريف الاهلاك", - "Interest Expense": "مصروفات الفوائد", - "Sales of Product Income": "مبيعات دخل المنتجات", - "Inventory Asset": "المخزون", - "Cost of Goods Sold (COGS)": "تكلفة البضائع المباعة (COGS)", - "Cost of Goods Sold": "تكلفة البضاعة المباعة", - "Accounts Payable": "الذمم الدائنة", - "Other Expense": "مصاريف أخرى", - "Payroll Expenses": "مصاريف المرتبات", - "Fixed Asset": "أصول ثابتة", - "Credit Card": "بطاقة إئتمان", - "Non-Current Asset": "أصول غير متداولة", - "Current Asset": "أصول متداولة", - "Other Asset": "أصول اخري", - "Long Term Liability": "التزامات طويلة الاجل", - "Current Liability": "التزامات قصيرة الاجل", - "Other Liability": "التزمات اخري", - "Equity": "حقوق الملكية", - "Expense": "مصروف", - "Income": "إيراد", - "Accounts Receivable (A/R)": "الذمم المدينة", - "Accounts Receivable": "الذمم المدينة", - "Accounts Payable (A/P)": "الذمم الدائنة", - "Inactive": "غير نشط", - "Other Current Asset": "أصول متداولة اخرى", - "Tax Payable": "الضريبة المستحقة", - "Other Current Liability": "التزامات قصيرة الأجر اخرى", - "Non-Current Liability": "التزامات طويلة الأجر", - "Assets": "أصول", - "Liabilities": "الالتزمات", - "Account name": "أسم الحساب", - "Account type": "نوع الحساب", - "Account normal": "حساب عادي", - "Description": "وصف", - "Account code": "رمز الحساب", - "Currency": "عملة", - "Balance": "توازن", - "Active": "نشيط", - "Created at": "أنشئت في", - "fixed_asset": "أصل ثابت", - "Journal": "قيد", - "Reconciliation": "تسوية", - "Credit": "دائن", - "Debit": "مدين", - "Interest": "فائدة", - "Depreciation": "اهلاك", - "Payroll": "كشف رواتب", - "Type": "نوع", - "Name": "الأسم", - "Sellable": "قابل للبيع", - "Purchasable": "قابل للشراء", - "Sell price": "سعر البيع", - "Cost price": "سعر الكلفة", - "User": "المستخدم", - "Category": "تصنيف", - "Note": "ملحوظة", - "Quantity on hand": "كمية في اليد", - "Purchase description": "وصف الشراء", - "Sell description": "وصف البيع", - "Sell account": "حساب البيع", - "Cost account": "حساب التكلفة", - "Inventory account": "حساب المخزون", - "Payment date": "تاريخ الدفع", - "Payment account": "حساب الدفع", - "Amount": "كمية", - "Reference No.": "رقم المرجع.", - "Published": "نشرت", - "Journal number": "رقم القيد", - "Status": "حالة", - "Journal type": "نوع القيد", - "Date": "تاريخ", - "Asset": "أصل", - "Liability": "التزام", - "First-in first-out (FIFO)": "الوارد أولاً يصرف أولاً (FIFO)", - "Last-in first-out (LIFO)": "الوارد أخيرًا يصرف أولاً (LIFO)", - "Average rate": "المعدل المتوسط", - "Total": "الإجمالي", - "Transaction type": "نوع المعاملة", - "Transaction #": "عملية #", - "Running Value": "القيمة الجارية", - "Running quantity": "الكمية الجارية", - "Profit Margin": "هامش الربح", - "Value": "القيمة", - "Rate": "السعر", - "OPERATING ACTIVITIES": "الأنشطة التشغيلية", - "FINANCIAL ACTIVITIES": "الأنشطة التمويلية", - "INVESTMENT ACTIVITIES": "الانشطة الاستثمارية", - "Net income": "صافي الدخل", - "Adjustments net income by operating activities.": "تسويات صافي الدخل من الأنشطة التشغيلية.", - "Net cash provided by operating activities": "صافي التدفقات النقدية من أنشطة التشغيل", - "Net cash provided by investing activities": "صافي التدفقات النقدية من أنشطة الاستثمار", - "Net cash provided by financing activities": "صافي التدفقات النقدية من أنشطة التمويلية", - "Cash at beginning of period": "التدفقات النقدية في بداية الفترة", - "NET CASH INCREASE FOR PERIOD": "زيادة التدفقات النقدية للفترة", - "CASH AT END OF PERIOD": "صافي التدفقات النقدية في نهاية الفترة", - "Expenses": "مصاريف", - "Services": "خدمات", - "Inventory": "المخزون", - "Non Inventory": "غير المخزون", - "Draft": "مسودة", - "Delivered": "تم التوصيل", - "Overdue": "متأخر", - "Partially paid": "المدفوعة جزئيا", - "Paid": "مدفوع", - "Opened": "افتتح", - "Unpaid": "غير مدفوعة", - "Approved": "وافق", - "Rejected": "مرفوض", - "Invoiced": "مفوترة", - "Expired": "منتهي الصلاحية", - "Closed": "مغلق", - "Manual journal": "قيد اليدوي", - "Owner contribution": "زيادة رأس المال", - "Transfer to account": "تحويل إلى الحساب", - "Transfer from account": "تحويل من الحساب", - "Other income": "إيراد اخر", - "Other expense": "مصاريف أخرى", - "Owner drawing": "سحب رأس المال", - "Inventory adjustment": "تسوية المخزون", - "Customer opening balance": "الرصيد الافتتاحي للزبون", - "Vendor opening balance": "رصيد افتتاحي للمورد", - "Payment made": "سند الزبون", - "Bill": "فاتورة الشراء", - "Payment receive": "استلام الدفع", - "Sale receipt": "إيصال البيع", - "Sale invoice": "فاتورة البيع", - "Quantity": "الكمية", - "Bank Account": "حساب البنك", - "Saving Bank Account": "حساب التوفير البنكي", - "Undeposited Funds": "الأموال غير المودعة", - "Computer Equipment": "معدات كمبيوتر", - "Office Equipment": "معدات مكتبية", - "Uncategorized Income": "الدخل غير مصنف", - "Sales of Service Income": "دخل مبيعات الخدمات", - "Bank Fees and Charges": "رسوم المصرفية", - "Exchange Gain or Loss": "ربح أو خسارة فروقات الصرف", - "Rent": "إيجار", - "Office expenses": "مصاريف المكتب", - "Other Expenses": "مصاريف اخري", - "Drawings": "السحوبات", - "Owner's Equity": "حقوق الملكية", - "Opening Balance Equity": "الارصدة الافتتاحية ", - "Retained Earnings": "الأرباح المحتجزة", - "Sales Tax Payable": "ضريبة المبيعات المستحقة", - "Revenue Received in Advance": "الإيرادات المقبوضة مقدما", - "Opening Balance Liabilities": "رصيد الالتزامات الافتتاحي", - "Loan": "اقراض", - "Owner A Drawings": "مسحوبات المالك", - "An account that holds valuation of products or goods that available for sale.": "حساب يحمل قيم مخزون البضاعة أو السلع المتاحة للبيع.", - "Tracks the gain and losses of the exchange differences.": "يسجل مكاسب وخسائر فروق الصرف.", - "Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "يتم تسجيل أي رسوم مصرفية يتم فرضها في حساب الرسوم والمصروفات البنكية. ومن الأمثلة على ذلك رسوم صيانة الحساب المصرفي ورسوم المعاملات ورسوم الدفع المتأخر.", - "The income activities are not associated to the core business.": "لا ترتبط انشطة الدخل إلى الأعمال الأساسية.", - "Cash and cash equivalents": "النقد والنقد المكافئ", - "Inventories": "مخزون البضاعة", - "Other current assets": "الأصول متداولة الأخرى", - "Non-Current Assets": "أصول غير المتداولة", - "Current Liabilties": "التزامات متداولة", - "Long-Term Liabilities": "التزامات طويلة الاجل", - "Non-Current Liabilities": "التزامات غير متداولة", - "Liabilities and Equity": "التزامات وحقوق الملكية", - "Closing balance": "الرصيد الختامي", - "Opening balance": "الرصيد الفتاحي", - "Total {{accountName}}": "إجمالي {{accountName}}", - - "invoice.paper.invoice": "فاتورة", - "invoice.paper.due_amount": "القيمة المستحقة", - "invoice.paper.billed_to": "فاتورة إلي", - "invoice.paper.invoice_date": "تاريخ الفاتورة", - "invoice.paper.invoice_number": "رقم الفاتورة", - "invoice.paper.due_date": "تاريخ الاستحقاق", - "invoice.paper.conditions_title": "الشروط والأحكام", - "invoice.paper.notes_title": "ملاحظات", - "invoice.paper.total": "المجموع", - "invoice.paper.balance_due": "مبلغ المستحق", - "invoice.paper.payment_amount": "مبلغ المدفوع", - "invoice.paper.invoice_amount": "قيمة الفاتورة", - - "item_entry.paper.item_name": "اسم الصنف", - "item_entry.paper.rate": "السعر", - "item_entry.paper.quantity": "الكمية", - "item_entry.paper.total": "إجمالي", - - "estimate.paper.estimate": "عرض أسعار", - "estimate.paper.billed_to": "عرض أسعار إلي", - "estimate.paper.estimate_date": "تاريخ العرض", - "estimate.paper.estimate_number": "رقم العرض", - "estimate.paper.expiration_date": "تاريخ انتهاء الصلاحية", - "estimate.paper.conditions_title": "الشروط والأحكام", - "estimate.paper.notes_title": "ملاحظات", - "estimate.paper.amount": "قيمة العرض", - "estimate.paper.subtotal": "المجموع", - "estimate.paper.total": "إجمالي", - "estimate.paper.estimate_amount": "قيمة العرض", - - "receipt.paper.receipt": "إيصال", - "receipt.paper.billed_to": "الإيصال إلي", - "receipt.paper.receipt_date": "تاريخ الإيصال", - "receipt.paper.receipt_number": "رقم الإيصال", - "receipt.paper.conditions_title": "الشروط والأحكام", - "receipt.paper.notes_title": "ملاحظات", - "receipt.paper.receipt_amount": "قيمة الإيصال", - "receipt.paper.total": "إجمالي", - "receipt.paper.payment_amount": "مبلغ المدفوع", - "receipt.paper.balance_due": "مبلغ المستحق", - "receipt.paper.statement": "البيان", - "receipt.paper.notes": "ملاحظات", - - "payment.paper.payment_receipt": "إيصال قبض", - "payment.paper.amount_received": "القيمة المستلمه", - "payment.paper.billed_to": "إيصال إلي", - "payment.paper.payment_date": "تاريخ الدفع", - "payment.paper.invoice_number": "رقم الفاتورة", - "payment.paper.invoice_date": "تاريخ الفاتورة", - "payment.paper.invoice_amount": "قيمة الفاتورة", - "payment.paper.payment_amount": "قيمة الدفع", - "payment.paper.balance_due": "المبلغ المستحق", - "payment.paper.statement": "البيان", - - "credit.paper.credit_note": "اشعار دائن", - "credit.paper.amount": "قيمة الاشعار", - "credit.paper.remaining": "رصيد المتبقي", - "credit.paper.billed_to": "إيصال إلي", - "credit.paper.credit_date": "تاريخ الاشعار", - "credit.paper.terms_conditions": "الشروط والاحكام", - "credit.paper.notes": "ملاحظات", - "credit.paper.total": "إجمالي", - "credit.paper.credits_used": "قيمة المستخدمه", - "credit.paper.credits_remaining": "قيمة المتبقية", - - "account.field.name": "إسم الحساب", - "account.field.description": "الوصف", - "account.field.slug": "Account slug", - "account.field.code": "رقم الحساب", - "account.field.root_type": "جذر الحساب", - "account.field.normal": "طبيعة الحساب", - "account.field.normal.credit": "دائن", - "account.field.normal.debit": "مدين", - "account.field.type": "نوع الحساب", - "account.field.active": "Activity", - "account.field.balance": "الرصيد", - "account.field.created_at": "أنشئت في", - "item.field.type": "نوع الصنف", - "item.field.type.inventory": "مخزون", - "item.field.type.service": "خدمة", - "item.field.type.non-inventory": "غير مخزون", - "item.field.name": "اسم الصنف", - "item.field.code": "رمز الصنف", - "item.field.sellable": "قابل للبيع", - "item.field.purchasable": "قابل للشراء", - "item.field.cost_price": "سعر التكلفة", - "item.field.cost_account": "حساب التكلفة", - "item.field.sell_account": "حساب البيع", - "item.field.sell_description": "وصف البيع", - "item.field.inventory_account": "حساب المخزون", - "item.field.purchase_description": "وصف الشراء", - "item.field.quantity_on_hand": "الكمية", - "item.field.note": "ملاحظة", - "item.field.category": "التصنيف", - "item.field.active": "Active", - "item.field.created_at": "أنشئت في", - "item_category.field.name": "الاسم", - "item_category.field.description": "الوصف", - "item_category.field.count": "العدد", - "item_category.field.created_at": "أنشئت في", - "invoice.field.customer": "الزبون", - "invoice.field.invoice_date": "تاريخ الفاتورة", - "invoice.field.due_date": "تاريخ الاستحقاق", - "invoice.field.invoice_no": "رقم الفاتورة", - "invoice.field.reference_no": "رقم الإشاري", - "invoice.field.invoice_message": "رسالة الفاتورة", - "invoice.field.terms_conditions": "الشروط والأحكام", - "invoice.field.amount": "القيمة", - "invoice.field.payment_amount": "القيمة المدفوعة", - "invoice.field.due_amount": "القيمة المستحقة", - "invoice.field.status": "الحالة", - "invoice.field.status.paid": "مدفوعة", - "invoice.field.status.partially-paid": "المدفوعة جزئيا", - "invoice.field.status.overdue": "متأخرة", - "invoice.field.status.unpaid": "غير مدفوعة", - "invoice.field.status.delivered": "تم تسليمها", - "invoice.field.status.draft": "مسودة", - "invoice.field.created_at": "أنشئت في", - "estimate.field.amount": "القيمة", - "estimate.field.estimate_number": "رقم العرض", - "estimate.field.customer": "الزبون", - "estimate.field.estimate_date": "تاريخ العرض", - "estimate.field.expiration_date": "تاريخ انتهاء الصلاحية", - "estimate.field.reference_no": "رقم الإشاري", - "estimate.field.note": "ملاحظة", - "estimate.field.terms_conditions": "الشروط والأحكام", - "estimate.field.status": "الحالة", - "estimate.field.status.delivered": "تم تسليمها", - "estimate.field.status.rejected": "مرفوضة", - "estimate.field.status.approved": "تم الموافقة", - "estimate.field.status.draft": "مسودة", - "estimate.field.created_at": "أنشئت في", - "payment_receive.field.customer": "الزبون", - "payment_receive.field.payment_date": "تاريخ الدفع", - "payment_receive.field.amount": "القيمة", - "payment_receive.field.reference_no": "رقم الإشاري", - "payment_receive.field.deposit_account": "حساب الإيداع", - "payment_receive.field.payment_receive_no": "رقم عملية الدفع", - "payment_receive.field.statement": "البيان", - "payment_receive.field.created_at": "أنشئت في", - "bill_payment.field.vendor": "المورد", - "bill_payment.field.amount": "القيمة", - "bill_payment.field.due_amount": "قيمة المستحقة", - "bill_payment.field.payment_account": "حساب الدفع", - "bill_payment.field.payment_number": "قيمة الدفع", - "bill_payment.field.payment_date": "تاريخ الدفع", - "bill_payment.field.reference_no": "رقم الإشاري", - "bill_payment.field.description": "الوصف", - "bill_payment.field.created_at": "أنشئت في", - "bill.field.vendor": "المورد", - "bill.field.bill_number": "رقم الفاتورة", - "bill.field.bill_date": "تاريخ الفاتورة", - "bill.field.due_date": "تاريخ الاستحقاق", - "bill.field.reference_no": "رقم الإشاري", - "bill.field.status": "الحالة", - "bill.field.status.paid": "مدفوعة", - "bill.field.status.partially-paid": "مدفوعة جزئيا", - "bill.field.status.unpaid": "غير مدفوعة", - "bill.field.status.opened": "مفتوحة", - "bill.field.status.draft": "مسودة", - "bill.field.status.overdue": "متأخرة", - "bill.field.amount": "القيمة", - "bill.field.payment_amount": "قيم الدفع", - "bill.field.note": "ملاحظة", - "bill.field.created_at": "أنشئت في", - "inventory_adjustment.field.date": "التاريخ", - "inventory_adjustment.field.type": "النوع", - "inventory_adjustment.field.type.increment": "زيادة", - "inventory_adjustment.field.type.decrement": "نقصان", - "inventory_adjustment.field.adjustment_account": "حساب التسوية", - "inventory_adjustment.field.reason": "السبب", - "inventory_adjustment.field.reference_no": "رقم الإشاري", - "inventory_adjustment.field.description": "الوصف", - "inventory_adjustment.field.published_at": "نشرت في", - "inventory_adjustment.field.created_at": "أنشئت في", - "expense.field.payment_date": "تاريخ الدفع", - "expense.field.payment_account": "حساب الدفع", - "expense.field.amount": "القيمة", - "expense.field.reference_no": "رقم الإشاري", - "expense.field.description": "الوصف", - "expense.field.published": "Published", - "expense.field.status": "الحالة", - "expense.field.status.draft": "مسودة", - "expense.field.status.published": "نشرت", - "expense.field.created_at": "أنشئت في", - "manual_journal.field.date": "التاريخ", - "manual_journal.field.journal_number": "رقم القيد", - "manual_journal.field.reference": "رقم الإشاري", - "manual_journal.field.journal_type": "نوع القيد", - "manual_journal.field.amount": "القيمة", - "manual_journal.field.description": "الوصف", - "manual_journal.field.status": "الحالة", - "manual_journal.field.created_at": "أنشئت في", - "receipt.field.amount": "القيمة", - "receipt.field.deposit_account": "حساب الإيداع", - "receipt.field.customer": "الزبون", - "receipt.field.receipt_date": "تاريخ الإيصال", - "receipt.field.receipt_number": "رقم الإيصال", - "receipt.field.reference_no": "رقم الإشاري", - "receipt.field.receipt_message": "رسالة الإيصال", - "receipt.field.statement": "البيان", - "receipt.field.created_at": "أنشئت في", - "receipt.field.status": "الحالة", - "receipt.field.status.draft": "مسودة", - "receipt.field.status.closed": "مغلقة", - "customer.field.first_name": "الاسم الأول", - "customer.field.last_name": "الاسم الاخير", - "customer.field.display_name": "اسم العرض", - "customer.field.email": "بريد الالكتروني", - "customer.field.work_phone": "هاتف عمل", - "customer.field.personal_phone": "هاتف شخصي", - "customer.field.company_name": "اسم الشركة", - "customer.field.website": "موقع الكتروني", - "customer.field.opening_balance_at": "الرصيد الافتتاحي في", - "customer.field.opening_balance": "الرصيد الافتتاحي", - "customer.field.created_at": "أنشئت في", - "customer.field.balance": "الرصيد", - "customer.field.status": "الحالة", - "customer.field.currency": "العملة", - "customer.field.status.active": "مفعل", - "customer.field.status.inactive": "غير مفعل", - "customer.field.status.overdue": "متأخر", - "customer.field.status.unpaid": "غير دافع", - "vendor.field.first_name": "الاسم الأول", - "vendor.field.last_name": "الاسم الاخير", - "vendor.field.display_name": "اسم العرض", - "vendor.field.email": "بريد الالكتروني", - "vendor.field.work_phone": "هاتف عمل", - "vendor.field.personal_phone": "هاتف شخصي", - "vendor.field.company_name": "اسم الشركة", - "vendor.field.website": "موقع الكتروني", - "vendor.field.opening_balance_at": "الرصيد الافتتاحي في", - "vendor.field.opening_balance": "الرصيد الافتتاحي", - "vendor.field.created_at": "أنشئت في", - "vendor.field.balance": "الرصيد", - "vendor.field.status": "الحالة", - "vendor.field.currency": "العملة", - "vendor.field.status.active": "مفعل", - "vendor.field.status.inactive": "غير مفعل", - "vendor.field.status.overdue": "متأخر", - "vendor.field.status.unpaid": "غير دافع", - "Invoice write-off": "شطب فاتورة", - "transaction_type.credit_note": "اشعار دائن", - "transaction_type.refund_credit_note": "استرجاع اموال اشعار دائن", - "transaction_type.vendor_credit": "اشعار مدين", - "transaction_type.refund_vendor_credit": "استرجاع اموال اشعار مدين", - "transaction_type.landed_cost": "تحميل تكلفة", - - "sms_notification.invoice_details.label": "تفاصيل فاتورة البيع ", - "sms_notification.invoice_reminder.label": "تذكير بفاتورة البيع ", - "sms_notification.receipt_details.label": "تفاصيل إيصال البيع ", - "sms_notification.sale_estimate_details.label": "تفاصيل فاتورة عرض اسعار ", - "sms_notification.payment_receive_details.label": "تفاصيل سند الزبون", - "sms_notification.customer_balance.label": "رصيد الزبون", - - "sms_notification.invoice_details.description": "سيتم إرسال إشعار عبر الرسائل القصيرة إلى العميل بمجرد إنشاء الفاتورة ونشرها أو عند إشعار العميل عبر رسالة نصية قصيرة بالفاتورة. ", - "sms_notification.payment_receive.description": "سيتم إرسال إشعار رسالة شكر للدفع إلى العميل بمجرد إنشاء الدفعة ونشرها أو إشعار العميل بالدفع يدويًا. ", - "sms_notification.receipt_details.description": "سيتم إرسال إشعار عبر الرسائل القصيرة إلى العميل بمجرد إنشاء ونشر الإيصال أو عند إشعار العميل بالإيصال يدويًا.", - "sms_notification.customer_balance.description": "إرسال رسالة نصية قصيرة إشعار العملاء برصيدهم الحالي المستحق. ", - "sms_notification.estimate_details.description": "سيتم إرسال إشعار عبر الرسائل القصيرة إلى عميلك بمجرد نشر العرض أو إشعار العميل بالعرض يدويًا.", - "sms_notification.invoice_reminder.description": "سيتم ارسال إشعار SMS لتذكير الزبون بالدفع باكراً ، سواء ارسال بشكل تلقائي او يدوي.", - - "sms_notification.customer_balance.default_message": "عزيزي {CustomerName} ، هذا تذكير بشأن رصيد الحالي المستحق {Balance} ، يُرجى الدفع في أقرب وقت ممكن. - {CompanyName}", - "sms_notification.payment_receive.default_message": "مرحبًا {CustomerName} ، تم القبض بقيمة {Amount} للفاتورة - {InvoiceNumber}. نحن نتطلع إلى خدمتك مرة أخرى. شكرا لك. - {CompanyName}", - "sms_notification.estimate.default_message": "مرحبًا , {CustomerName} ، تم أنشاء فاتورة عرض اسعار - {EstimateNumber} لك. يرجى إلقاء نظرة وقبوله للمضي قدما. بانتظار ردك. - {CompanyName}", - - "sms_notification.invoice_details.default_message": "مرحبًا {CustomerName}, لديك مبلغ مستحق قدره {DueAmount} للفاتورة {InvoiceNumber}. - {CompanyName}", - "sms_notification.receipt_details.default_message": "مرحبًا {CustomerName} ، لقد تم إنشاء إيصال - {ReceiptNumber} من أجلك. نتطلع إلى خدمتك مرة أخرى. شكرًا لك - {CompanyName}", - "sms_notification.invoice_reminder.default_message": "عزيزي {CustomerName} ، يرجي سداد فاتورة - {InvoiceNumber} المستحقة. يرجى الدفع قبل تاريخ {DueDate}. شكرا لك. - {CompanyName}", - - "module.sale_invoices.label": "فواتير البيع", - "module.sale_receipts.label": "إيصالات البيع", - "module.sale_estimates.label": "فاتورة عرض اسعار ", - "module.payment_receives.label": "سندات الزبائن ", - "module.customers.label": "العملاء", - - "sms_notification.invoice.var.invoice_number": "يشير إلى رقم الفاتورة.", - "sms_notification.invoice.var.reference_number": "يشير إلى رقم إشاري للفاتورة.", - "sms_notification.invoice.var.customer_name": "يشير إلى اسم العميل الفاتورة", - "sms_notification.invoice.var.due_amount": "يشير إلى مبلغ الفاتورة المستحق", - "sms_notification.invoice.var.amount": "يشير إلى مبلغ الفاتورة.", - "sms_notification.invoice.var.company_name": "يشير إلي اسم الشركة.", - "sms_notification.invoice.var.due_date": "يشير إلي تاريخ استحقاق الفاتورة.", - - "sms_notification.receipt.var.receipt_number": "يشير إلى رقم الإيصال.", - "sms_notification.receipt.var.reference_number": "يشير إلى رقم الإشاري للإيصال.", - "sms_notification.receipt.var.customer_name": "يشير إلى اسم العميل الإيصال.", - "sms_notification.receipt.var.amount": "يشير إلى مبلغ الإيصال. ", - "sms_notification.receipt.var.company_name": "يشير إلي اسم الشركة.", - - "sms_notification.payment.var.payment_number": "يشير إلى رقم معاملة الدفع.", - "sms_notification.payment.var.reference_number": "يشير إلى رقم الإشاري لعملية الدفع ", - "sms_notification.payment.var.customer_name": "يشير إلى اسم العميل الدفع", - "sms_notification.payment.var.amount": "يشير إلى مبلغ معاملة الدفع.", - "sms_notification.payment.company_name": "يشير إلي اسم الشركة.", - "sms_notification.payment.var.invoice_number": "يشير إلي رقم فاتورة التي تم دفعها.", - - "sms_notification.estimate.var.estimate_number": "يشير إلى رقم فاتورة عرض اسعار.", - "sms_notification.estimate.var.reference_number": "يشير إلى رقم الإشاري لفاتورة عرض اسعار.", - "sms_notification.estimate.var.customer_name": "يشير إلى اسم العميل الفاتورة", - "sms_notification.estimate.var.amount": "يشير إلى قيمة الفاتورة", - "sms_notification.estimate.var.company_name": "يشير إلي اسم الشركة.", - "sms_notification.estimate.var.expiration_date": "يشير إلي تاريخ الصلاحية الفاتورة.", - "sms_notification.estimate.var.estimate_date": "يشير إلي تاريخ الفاتورة.", - - "sms_notification.customer.var.customer_name": "يشير إلي اسم الزبون", - "sms_notification.customer.var.balance": "يشير إلي رصيد زبون المستحق.", - "sms_notification.customer.var.company_name": "يشير إلي اسم الشركة.", - - "ability.accounts": "شجرة الحسابات", - "ability.manual_journal": "القيود اليدوية", - "ability.cashflow": "التدفقات النقدية", - "ability.inventory_adjustment": "تسويات المخزون", - "ability.customers": "الزبائن", - "ability.vendors": "الموردين", - "ability.sale_estimates": "فواتير عرض الاسعار", - "ability.sale_invoices": "فواتير البيع", - "ability.sale_receipts": "إيصالات البيع", - "ability.expenses": "المصاريف", - "ability.payments_receive": "سندات الزبائن", - "ability.purchase_invoices": "فواتير الشراء", - "ability.all_reports": "كل التقارير", - "ability.payments_made": "سندات الموردين", - "ability.preferences": "التفضيلات", - "ability.mutate_system_preferences": "تعديل تفضيلات النظام.", - - "ability.items": "الأصناف", - "ability.view": "عرض", - "ability.create": "إضافة", - "ability.edit": "تعديل", - "ability.delete": "حذف", - "ability.transactions_locking": "إمكانية اغلاق المعاملات.", - - "ability.balance_sheet_report": "ميزانية العمومية", - "ability.profit_loss_sheet": "قائمة الدخل", - "ability.journal": "اليومية العامة", - "ability.general_ledger": "دفتر الأستاذ العام", - "ability.cashflow_report": "تقرير التدفقات النقدية", - "ability.AR_aging_summary_report": "ملخص اعمار الديون للذمم المدينة", - "ability.AP_aging_summary_report": "ملخص اعمار الديون للذمم الدائنة", - "ability.purchases_by_items": "المشتريات حسب المنتجات", - "ability.sales_by_items_report": "المبيعات حسب المنتجات", - "ability.customers_transactions_report": "معاملات الزبائن", - "ability.vendors_transactions_report": "معاملات الموردين", - "ability.customers_summary_balance_report": "ملخص أرصدة الزبائن", - "ability.vendors_summary_balance_report": "ملخص أرصدة الموردين", - "ability.inventory_valuation_summary": "ملخص تقييم المخزون", - "ability.inventory_items_details": "تفاصيل منتج المخزون", - - "vendor_credit.field.vendor": "المورد", - "vendor_credit.field.amount": "القيمة", - "vendor_credit.field.currency_code": "العملة", - "vendor_credit.field.credit_date": "تاريخ الاشعار", - "vendor_credit.field.credit_number": "رقم الاشعار", - "vendor_credit.field.note": "ملاحظة", - "vendor_credit.field.created_at": "أنشئت في", - "vendor_credit.field.reference_no": "رقم الإشاري", - - "vendor_credit.field.status": "الحالة", - "vendor_credit.field.status.draft": "مسودة", - "vendor_credit.field.status.published": "تم نشرها", - "vendor_credit.field.status.open": "مفتوحة", - "vendor_credit.field.status.closed": "مغلقة", - - "credit_note.field.terms_conditions": "الشروط والاحكام", - "credit_note.field.note": "ملاحظة", - "credit_note.field.currency_code": "العملة", - "credit_note.field.created_at": "أنشئت في", - "credit_note.field.amount": "القيمة", - "credit_note.field.credit_note_number": "رقم الاشعار", - "credit_note.field.credit_note_date": "تاريخ الاشعار", - "credit_note.field.customer": "الزبون", - "credit_note.field.reference_no": "رقم الإشاري", - - "credit_note.field.status": "الحالة", - "credit_note.field.status.draft": "مسودة", - "credit_note.field.status.published": "تم نشرها", - "credit_note.field.status.open": "مفتوحة", - "credit_note.field.status.closed": "مغلقة", - - "transactions_locking.module.sales.label": "المبيعات", - "transactions_locking.module.purchases.label": "المشتريات", - "transactions_locking.module.financial.label": "المالية", - "transactions_locking.module.all_transactions": "كل المعاملات", - - "transactions_locking.module.sales.desc": "فواتير البيع ، والإيصالات ، والإشعارات الدائنة ، واستلام مدفوعات الزبائن ، والأرصدة الافتتاحية للزبائن.", - "transactions_locking.module.purchases.desc": "فواتير الشراء ومدفوعات الموردين وإشعارات المدينة والأرصدة الافتتاحية للموردين.", - "transactions_locking.module.financial.desc": "القيود اليدوية والمصروفات وتسويات المخزون.", - - "inventory_adjustment.type.increment": "زيادة", - "inventory_adjustment.type.decrement": "نقصان", - - "customer.type.individual": "فرد", - "customer.type.business": "اعمال", - - "credit_note.view.draft": "مسودة", - "credit_note.view.closed": "مغلقة", - "credit_note.view.open": "مفتوحة", - "credit_note.view.published": "نشرت", - - "vendor_credit.view.draft": "مسودة", - "vendor_credit.view.closed": "مغلقة", - "vendor_credit.view.open": "مفتوحة", - "vendor_credit.view.published": "نشرت", - - "allocation_method.value.label": "القيمة", - "allocation_method.quantity.label": "الكمية", - - "balance_sheet.assets": "الأصول", - "balance_sheet.current_asset": "الأصول المتداولة", - "balance_sheet.cash_and_cash_equivalents": "النقدية وما يعادلها", - "balance_sheet.accounts_receivable": "الذمم المدينة", - "balance_sheet.inventory": "المخزون", - "balance_sheet.other_current_assets": "اصول متداولة اخرى", - "balance_sheet.fixed_asset": "الأصول الثابتة", - "balance_sheet.non_current_assets": "الاصول غير المتداولة", - "balance_sheet.liabilities_and_equity": "الالتزامات وحقوق الملكية", - "balance_sheet.liabilities": "الإلتزامات", - "balance_sheet.current_liabilties": "الالتزامات المتداولة", - "balance_sheet.long_term_liabilities": "الالتزامات طويلة الاجل", - "balance_sheet.non_current_liabilities": "الالتزامات غير المتداولة", - "balance_sheet.equity": "حقوق الملكية", - - "balance_sheet.account_name": "اسم الحساب", - "balance_sheet.total": "إجمالي", - "balance_sheet.percentage_of_column": "٪ التغير العمودي", - "balance_sheet.percentage_of_row": "٪ التغير الأفقي", - - "financial_sheet.previoud_period_date": "(ف.س) {{date}}", - "fianncial_sheet.previous_period_change": "التغيرات (ف.س)", - "financial_sheet.previous_period_percentage": "٪ التغير (ف.س)", - - "financial_sheet.previous_year_date": "(س.س) {{date}}", - "financial_sheet.previous_year_change": "التغيرات (س.س)", - "financial_sheet.previous_year_percentage": "٪ التغير (س.س)", - "financial_sheet.total_row": "إجمالي {{value}}", - - "profit_loss_sheet.income": "الإيرادات", - "profit_loss_sheet.cost_of_sales": "تكلفة المبيعات", - "profit_loss_sheet.gross_profit": "إجمالي الدخل", - "profit_loss_sheet.expenses": "المصروفات", - "profit_loss_sheet.net_operating_income": "صافي الدخل التشغيلي", - "profit_loss_sheet.other_income": "إيرادات اخري", - "profit_loss_sheet.other_expenses": "مصاريف اخري", - "profit_loss_sheet.net_income": "صافي الدخل", - - "profit_loss_sheet.account_name": "اسم الحساب", - "profit_loss_sheet.total": "إجمالي", - - "profit_loss_sheet.percentage_of_income": "٪ التغير في الإيرادات", - "profit_loss_sheet.percentage_of_expenses": "٪ التغير في المصاريف", - "profit_loss_sheet.percentage_of_column": "٪ التغير العمودي", - "profit_loss_sheet.percentage_of_row": "٪ التغير الأفقي", - - "warehouses.primary_warehouse": "المستودع الرئيسي", - "branches.head_branch": "الفرع الرئيسي", - - "account.accounts_payable.currency": "الذمم الدائنة - {{currency}}", - "account.accounts_receivable.currency": "الذمم المدينة - {{currency}}", - - "role.admin.name": "الادارة", - "role.admin.desc": "وصول غير مقيد لجميع الوحدات.", - - "role.staff.name": "العاملين", - "role.staff.desc": "الوصول إلى جميع الوحدات باستثناء التقارير والإعدادات والمحاسبة.", - - "warehouse_transfer.view.draft.name": "مسودة", - "warehouse_transfer.view.in_transit.name": "في النقل", - "warehouse_transfer.view.transferred.name": "تم النقل" -} \ No newline at end of file diff --git a/packages/server/src/locales/en.json b/packages/server/src/locales/en.json deleted file mode 100644 index 293186e9e..000000000 --- a/packages/server/src/locales/en.json +++ /dev/null @@ -1,642 +0,0 @@ -{ - "Petty Cash": "Petty Cash", - "Cash": "Cash", - "Bank": "Bank", - "Other Income": "Other Income", - "Interest Income": "Interest Income", - "Depreciation Expense": "Depreciation Expense", - "Interest Expense": "Interest Expense", - "Sales of Product Income": "Sales of Product Income", - "Inventory Asset": "Inventory Asset", - "Cost of Goods Sold (COGS)": "Cost of Goods Sold (COGS)", - "Cost of Goods Sold": "Cost of Goods Sold", - "Accounts Payable": "Accounts Payable", - "Other Expense": "Other Expense", - "Payroll Expenses": "Payroll Expenses", - "Fixed Asset": "Fixed Asset", - "Credit Card": "Credit Card", - "Non-Current Asset": "Non-Current Asset", - "Current Asset": "Current Asset", - "Other Asset": "Other Asset", - "Long Term Liability": "Long Term Liability", - "Current Liability": "Current Liability", - "Other Liability": "Other Liability", - "Equity": "Equity", - "Expense": "Expense", - "Income": "Income", - "Accounts Receivable (A/R)": "Accounts Receivable (A/R)", - "Accounts Receivable": "Accounts Receivable", - "Accounts Payable (A/P)": "Accounts Payable (A/P)", - "Inactive": "Inactive", - "Other Current Asset": "Other Current Asset", - "Tax Payable": "Tax Payable", - "Other Current Liability": "Other Current Liability", - "Non-Current Liability": "Non-Current Liability", - "Assets": "Assets", - "Liabilities": "Liabilities", - "Account name": "Account name", - "Account type": "Account type", - "Account normal": "Account normal", - "Description": "Description", - "Account code": "Account code", - "Currency": "Currency", - "Balance": "Balance", - "Active": "Active", - "Created at": "Created at", - "fixed_asset": "Fixed asset", - "Journal": "Journal", - "Reconciliation": "Reconciliation", - "Credit": "Credit", - "Debit": "Debit", - "Interest": "Interest", - "Depreciation": "Depreciation", - "Payroll": "Payroll", - "Type": "Type", - "Name": "Name", - "Sellable": "Sellable", - "Purchasable": "Purchasable", - "Sell price": "Sell price", - "Cost price": "Cost price", - "User": "User", - "Category": "Category", - "Note": "Note", - "Quantity on hand": "Quantity on hand", - "Quantity": "Quantity", - "Purchase description": "Purchase description", - "Sell description": "Sell description", - "Sell account": "Sell account", - "Cost account": "Cost account", - "Inventory account": "Inventory account", - "Payment date": "Payment date", - "Payment account": "Payment account", - "Amount": "Amount", - "Reference No.": "Reference No.", - "Journal number": "Journal number", - "Status": "Status", - "Journal type": "Journal type", - "Date": "Date", - "Asset": "Asset", - "Liability": "Liability", - "First-in first-out (FIFO)": "First-in first-out (FIFO)", - "Last-in first-out (LIFO)": "Last-in first-out (LIFO)", - "Average rate": "Average rate", - "Total": "Total", - "Transaction type": "Transaction type", - "Transaction #": "Transaction #", - "Running Value": "Running Value", - "Running quantity": "Running quantity", - "Profit Margin": "Profit Margin", - "Value": "Value", - "Rate": "Rate", - "OPERATING ACTIVITIES": "OPERATING ACTIVITIES", - "FINANCIAL ACTIVITIES": "FINANCIAL ACTIVITIES", - "Net income": "Net income", - "Adjustments net income by operating activities.": "Adjustments net income by operating activities.", - "Net cash provided by operating activities": "Net cash provided by operating activities", - "Net cash provided by investing activities": "Net cash provided by investing activities", - "Net cash provided by financing activities": "Net cash provided by financing activities", - "Cash at beginning of period": "Cash at beginning of period", - "NET CASH INCREASE FOR PERIOD": "NET CASH INCREASE FOR PERIOD", - "CASH AT END OF PERIOD": "CASH AT END OF PERIOD", - "Expenses": "Expenses", - "Services": "Services", - "Inventory": "Inventory", - "Non Inventory": "Non Inventory", - "Draft": "Draft", - "Published": "Published", - "Delivered": "Delivered", - "Overdue": "Overdue", - "Partially paid": "Partially paid", - "Paid": "Paid", - "Opened": "Opened", - "Unpaid": "Unpaid", - "Approved": "Approved", - "Rejected": "Rejected", - "Invoiced": "Invoiced", - "Expired": "Expired", - "Closed": "Closed", - "Manual journal": "Manual journal", - "Owner contribution": "Owner contribution", - "Transfer to account": "Transfer to account", - "Transfer from account": "Transfer from account", - "Other income": "Other income", - "Other expense": "Other expense", - "Owner drawing": "Owner drawing", - "Inventory adjustment": "Inventory adjustment", - "Customer opening balance": "Customer opening balance", - "Vendor opening balance": "Vendor opening balance", - "Payment made": "Payment made", - "Bill": "Bill", - "Payment receive": "Payment receive", - "Sale receipt": "Sale receipt", - "Sale invoice": "Sale invoice", - "Bank Account": "Bank Account", - "Saving Bank Account": "Saving Bank Account", - "Undeposited Funds": "Undeposited Funds", - "Computer Equipment": "Computer Equipment", - "Office Equipment": "Office Equipment", - "Uncategorized Income": "Uncategorized Income", - "Sales of Service Income": "Sales of Service Income", - "Bank Fees and Charges": "Bank Fees and Charges", - "Exchange Gain or Loss": "Exchange Gain or Loss", - "Rent": "Rent", - "Office expenses": "Office expenses", - "Other Expenses": "Other Expenses", - "Drawings": "Drawings", - "Owner's Equity": "Owner's Equity", - "Opening Balance Equity": "Opening Balance Equity", - "Retained Earnings": "Retained Earnings", - "Sales Tax Payable": "Sales Tax Payable", - "Revenue Received in Advance": "Revenue Received in Advance", - "Opening Balance Liabilities": "Opening Balance Liabilities", - "Loan": "Loan", - "Owner A Drawings": "Owner A Drawings", - "An account that holds valuation of products or goods that available for sale.": "An account that holds valuation of products or goods that available for sale.", - "Tracks the gain and losses of the exchange differences.": "Tracks the gain and losses of the exchange differences.", - "Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.": "Any bank fees levied is recorded into the bank fees and charges account. A bank account maintenance fee, transaction charges, a late payment fee are some examples.", - "The income activities are not associated to the core business.": "The income activities are not associated to the core business.", - "Cash and cash equivalents": "Cash and cash equivalents", - "Inventories": "Inventories", - "Other current assets": "Other current assets", - "Non-Current Assets": "Non-Current Assets", - "Current Liabilties": "Current Liabilties", - "Long-Term Liabilities": "Long-Term Liabilities", - "Non-Current Liabilities": "Non-Current Liabilities", - "Liabilities and Equity": "Liabilities and Equity", - "Closing balance": "Closing balance", - "Opening Balance": "Opening balance", - "Total {{accountName}}": "Total {{accountName}}", - "invoice.paper.invoice": "Invoice", - "invoice.paper.invoice_amount": "Invoice amount", - "invoice.paper.due_amount": "Due amount", - "invoice.paper.billed_to": "Billed to", - "invoice.paper.invoice_date": "Invoice date", - "invoice.paper.invoice_number": "Invoice No.", - "invoice.paper.due_date": "Due date", - "invoice.paper.conditions_title": "Conditions & terms", - "invoice.paper.notes_title": "Notes", - "invoice.paper.total": "Total", - "invoice.paper.payment_amount": "Payment Amount", - "invoice.paper.balance_due": "Balance Due", - - "item_entry.paper.item_name": "Item name", - "item_entry.paper.rate": "Rate", - "item_entry.paper.quantity": "Quantity", - "item_entry.paper.total": "Total", - - "estimate.paper.estimate": "Estimate", - "estimate.paper.estimate_amount": "Estimate amount", - "estimate.paper.billed_to": "Billed to", - "estimate.paper.estimate_date": "Estimate date", - "estimate.paper.estimate_number": "Estimate number", - "estimate.paper.expiration_date": "Expiration date", - "estimate.paper.conditions_title": "Conditions & terms", - "estimate.paper.notes_title": "Notes", - "estimate.paper.amount": "Estimate amount", - "estimate.paper.subtotal": "Subtotal", - "estimate.paper.total": "Total", - - "receipt.paper.receipt": "Receipt", - "receipt.paper.billed_to": "Billed to", - "receipt.paper.receipt_date": "Receipt date", - "receipt.paper.receipt_number": "Receipt number", - "receipt.paper.expiration_date": "Expiration date", - "receipt.paper.conditions_title": "Conditions & terms", - "receipt.paper.notes": "Notes", - "receipt.paper.statement": "Statement", - "receipt.paper.receipt_amount": "Receipt amount", - "receipt.paper.total": "Total", - "receipt.paper.balance_due": "Balance Due", - "receipt.paper.payment_amount": "Payment Amount", - - "credit.paper.credit_note": "Credit Note", - "credit.paper.remaining": "Credit remaining", - "credit.paper.amount": "Credit amount", - "credit.paper.billed_to": "Bill to", - "credit.paper.credit_date": "Credit date", - "credit.paper.total": "Total", - "credit.paper.credits_used": "Credits used", - "credit.paper.credits_remaining": "Credits remaining", - "credit.paper.conditions_title": "Conditions & terms", - "credit.paper.notes": "Notes", - - "payment.paper.payment_receipt": "Payment Receipt", - "payment.paper.amount_received": "Amount received", - "payment.paper.billed_to": "Billed to", - "payment.paper.payment_date": "Payment date", - "payment.paper.invoice_number": "Invoice number", - "payment.paper.invoice_date": "Invoice date", - "payment.paper.invoice_amount": "Invoice amount", - "payment.paper.payment_amount": "Payment amount", - "payment.paper.balance_due": "Balance Due", - "payment.paper.statement": "Statement", - - "account.field.name": "Account name", - "account.field.description": "Description", - "account.field.slug": "Account slug", - "account.field.code": "Account code", - "account.field.root_type": "Root type", - "account.field.normal": "Account normal", - "account.field.normal.credit": "Credit", - "account.field.normal.debit": "Debit", - "account.field.type": "Type", - "account.field.active": "Activity", - "account.field.balance": "Balance", - "account.field.created_at": "Created at", - "item.field.type": "Item type", - "item.field.type.inventory": "Inventory", - "item.field.type.service": "Service", - "item.field.type.non-inventory": "Non inventory", - "item.field.name": "Name", - "item.field.code": "Code", - "item.field.sellable": "Sellable", - "item.field.purchasable": "Purchasable", - "item.field.cost_price": "Cost price", - "item.field.cost_account": "Cost account", - "item.field.sell_account": "Sell account", - "item.field.sell_description": "Sell description", - "item.field.inventory_account": "Inventory account", - "item.field.purchase_description": "Purchase description", - "item.field.quantity_on_hand": "Quantity on hand", - "item.field.note": "Note", - "item.field.category": "Category", - "item.field.active": "Active", - "item.field.created_at": "Created at", - "item_category.field.name": "Name", - "item_category.field.description": "Description", - "item_category.field.count": "Count", - "item_category.field.created_at": "Created at", - "invoice.field.customer": "Customer", - "invoice.field.invoice_date": "Invoice date", - "invoice.field.due_date": "Due date", - "invoice.field.invoice_no": "Invoice No.", - "invoice.field.reference_no": "Reference No.", - "invoice.field.invoice_message": "Invoice message", - "invoice.field.terms_conditions": "Terms & conditions", - "invoice.field.amount": "Amount", - "invoice.field.payment_amount": "Payment amount", - "invoice.field.due_amount": "Due amount", - "invoice.field.status": "Status", - "invoice.field.status.paid": "Paid", - "invoice.field.status.partially-paid": "Partially paid", - "invoice.field.status.overdue": "Overdue", - "invoice.field.status.unpaid": "Unpaid", - "invoice.field.status.delivered": "Delivered", - "invoice.field.status.draft": "Draft", - "invoice.field.created_at": "Created at", - "estimate.field.amount": "Amount", - "estimate.field.estimate_number": "Estimate number", - "estimate.field.customer": "Customer", - "estimate.field.estimate_date": "Estimate date", - "estimate.field.expiration_date": "Expiration date", - "estimate.field.reference_no": "Reference No.", - "estimate.field.note": "Note", - "estimate.field.terms_conditions": "Terms & conditions", - "estimate.field.status": "Status", - "estimate.field.status.delivered": "Delivered", - "estimate.field.status.rejected": "Rejected", - "estimate.field.status.approved": "Approved", - "estimate.field.status.draft": "Draft", - "estimate.field.created_at": "Created at", - "payment_receive.field.customer": "Customer", - "payment_receive.field.payment_date": "Payment date", - "payment_receive.field.amount": "Amount", - "payment_receive.field.reference_no": "Reference No.", - "payment_receive.field.deposit_account": "Deposit account", - "payment_receive.field.payment_receive_no": "Payment receive No.", - "payment_receive.field.statement": "Statement", - "payment_receive.field.created_at": "Created at", - "bill_payment.field.vendor": "Vendor", - "bill_payment.field.amount": "Amount", - "bill_payment.field.due_amount": "Due amount", - "bill_payment.field.payment_account": "Payment account", - "bill_payment.field.payment_number": "Payment number", - "bill_payment.field.payment_date": "Payment date", - "bill_payment.field.reference_no": "Reference No.", - "bill_payment.field.description": "Description", - "bill_payment.field.created_at": "Created at", - "bill.field.vendor": "Vendor", - "bill.field.bill_number": "Bill number", - "bill.field.bill_date": "Bill date", - "bill.field.due_date": "Due date", - "bill.field.reference_no": "Reference No.", - "bill.field.status": "Status", - "bill.field.status.paid": "Paid", - "bill.field.status.partially-paid": "Partially paid", - "bill.field.status.unpaid": "Unpaid", - "bill.field.status.opened": "Opened", - "bill.field.status.draft": "Draft", - "bill.field.status.overdue": "overdue", - "bill.field.amount": "Amount", - "bill.field.payment_amount": "Payment amount", - "bill.field.note": "Note", - "bill.field.created_at": "Created at", - "inventory_adjustment.field.date": "Date", - "inventory_adjustment.field.type": "Type", - "inventory_adjustment.field.type.increment": "Increment", - "inventory_adjustment.field.type.decrement": "Decrement", - "inventory_adjustment.field.adjustment_account": "Adjustment account", - "inventory_adjustment.field.reason": "Reason", - "inventory_adjustment.field.reference_no": "Reference No.", - "inventory_adjustment.field.description": "Description", - "inventory_adjustment.field.published_at": "Published at", - "inventory_adjustment.field.created_at": "Created at", - "expense.field.payment_date": "Payment date", - "expense.field.payment_account": "Payment account", - "expense.field.amount": "Amount", - "expense.field.reference_no": "Reference No.", - "expense.field.description": "Description", - "expense.field.published": "Published", - "expense.field.status": "Status", - "expense.field.status.draft": "Draft", - "expense.field.status.published": "Published", - "expense.field.created_at": "Created at", - "manual_journal.field.date": "Date", - "manual_journal.field.journal_number": "Journal number", - "manual_journal.field.reference": "Reference No.", - "manual_journal.field.journal_type": "Journal type", - "manual_journal.field.amount": "Amount", - "manual_journal.field.description": "Description", - "manual_journal.field.status": "Status", - "manual_journal.field.created_at": "Created at", - "receipt.field.amount": "Amount", - "receipt.field.deposit_account": "Deposit account", - "receipt.field.customer": "Customer", - "receipt.field.receipt_date": "Receipt date", - "receipt.field.receipt_number": "Receipt number", - "receipt.field.reference_no": "Reference No.", - "receipt.field.receipt_message": "Receipt message", - "receipt.field.statement": "Statement", - "receipt.field.created_at": "Created at", - "receipt.field.status": "Status", - "receipt.field.status.draft": "Draft", - "receipt.field.status.closed": "Closed", - "customer.field.first_name": "First name", - "customer.field.last_name": "Last name", - "customer.field.display_name": "Display name", - "customer.field.email": "Email", - "customer.field.work_phone": "Work phone", - "customer.field.personal_phone": "Personal phone", - "customer.field.company_name": "Company name", - "customer.field.website": "Website", - "customer.field.opening_balance_at": "Opening balance at", - "customer.field.opening_balance": "Opening balance", - "customer.field.created_at": "Created at", - "customer.field.balance": "Balance", - "customer.field.status": "Status", - "customer.field.currency": "Curreny", - "customer.field.status.active": "Active", - "customer.field.status.inactive": "Inactive", - "customer.field.status.overdue": "Overdue", - "customer.field.status.unpaid": "Unpaid", - "vendor.field.first_name": "First name", - "vendor.field.last_name": "Last name", - "vendor.field.display_name": "Display name", - "vendor.field.email": "Email", - "vendor.field.work_phone": "Work phone", - "vendor.field.personal_phone": "Personal phone", - "vendor.field.company_name": "Company name", - "vendor.field.website": "Website", - "vendor.field.opening_balance_at": "Opening balance at", - "vendor.field.opening_balance": "Opening balance", - "vendor.field.created_at": "Created at", - "vendor.field.balance": "Balance", - "vendor.field.status": "Status", - "vendor.field.currency": "Curreny", - "vendor.field.status.active": "Active", - "vendor.field.status.inactive": "Inactive", - "vendor.field.status.overdue": "Overdue", - "vendor.field.status.unpaid": "Unpaid", - "Invoice write-off": "Invoice write-off", - - "transaction_type.credit_note": "Credit note", - "transaction_type.refund_credit_note": "Refund credit note", - "transaction_type.vendor_credit": "Vendor credit", - "transaction_type.refund_vendor_credit": "Refund vendor credit", - "transaction_type.landed_cost": "Landed cost", - - "sms_notification.invoice_details.label": "Sale invoice details", - "sms_notification.invoice_reminder.label": "Sale invoice reminder", - "sms_notification.receipt_details.label": "Sale receipt details", - "sms_notification.sale_estimate_details.label": "Sale estimate details", - "sms_notification.payment_receive_details.label": "Payment receive details", - "sms_notification.customer_balance.label": "Customer balance", - - "sms_notification.invoice_details.description": "SMS notification will be sent to your customer once invoice created and published or when notify customer via SMS about the invoice.", - "sms_notification.payment_receive.description": "Payment thank you message notification will be sent to customer once the payment created and published or notify customer about payment manually.", - "sms_notification.receipt_details.description": "SMS notification will be sent to your cusotmer once receipt created and published or when notify customer about the receipt manually.", - "sms_notification.customer_balance.description": "Send SMS to notify customers about their current outstanding balance.", - "sms_notification.estimate_details.description": "SMS notification will be sent to your customer once estimate publish or notify customer about estimate manually.", - "sms_notification.invoice_reminder.description": "SMS notification will be sent to remind the customer to pay earliest, either automatically or manually.", - - "sms_notification.customer_balance.default_message": "Dear {CustomerName}, This is reminder about your current outstanding balance of {Balance}, Please pay at the earliest. - {CompanyName}", - "sms_notification.payment_receive.default_message": "'Hi, {CustomerName}, We have received your payment for the invoice - {InvoiceNumber}. We look forward to serving you again. Thank you. - {CompanyName}'", - "sms_notification.estimate.default_message": "Hi, {CustomerName}, We have created an estimate - {EstimateNumber} for you. Please take a look and accept it to proceed further. Looking forward to hearing from you. - {CompanyName}", - - "sms_notification.invoice_details.default_message": "Hi, {CustomerName}, You have an outstanding amount of {DueAmount} for the invoice {InvoiceNumber}. - {CompanyName}", - "sms_notification.receipt_details.default_message": "Hi, {CustomerName}, We have created receipt - {ReceiptNumber} for you. we look forward to serveing you again. Thank your - {CompanyName}", - "sms_notification.invoice_reminder.default_message": "Dear {CustomerName}, The payment towards the invoice - {InvoiceNumber} is due. Please pay before {DueDate}. Thank you. - {CompanyName}", - - "module.sale_invoices.label": "Sale invoices", - "module.sale_receipts.label": "Sale receipts", - "module.sale_estimates.label": "Sale estimates", - "module.payment_receives.label": "Payment receive", - "module.customers.label": "Customers", - - "sms_notification.invoice.var.invoice_number": "References to invoice number.", - "sms_notification.invoice.var.reference_number": "References to invoice reference number.", - "sms_notification.invoice.var.customer_name": "References to invoice customer name.", - "sms_notification.invoice.var.due_amount": "References to invoice due amount.", - "sms_notification.invoice.var.amount": "References to invoice amount.", - "sms_notification.invoice.var.company_name": "References to company name.", - "sms_notification.invoice.var.due_date": "References to invoice due date.", - - "sms_notification.receipt.var.receipt_number": "References to receipt number.", - "sms_notification.receipt.var.reference_number": "References to receipt reference number.", - "sms_notification.receipt.var.customer_name": "References to receipt customer name.", - "sms_notification.receipt.var.amount": "References to receipt amount.", - "sms_notification.receipt.var.company_name": "References to company name.", - - "sms_notification.payment.var.payment_number": "References to payment transaction number.", - "sms_notification.payment.var.reference_number": "References to payment reference number", - "sms_notification.payment.var.customer_name": "References to payment customer name.", - "sms_notification.payment.var.amount": "References to payment transaction amount.", - "sms_notification.payment.company_name": "References to company name", - "sms_notification.payment.var.invoice_number": "Reference to payment invoice number.", - - "sms_notification.estimate.var.estimate_number": "References to estimate number.", - "sms_notification.estimate.var.reference_number": "References to estimate reference number.", - "sms_notification.estimate.var.customer_name": "References to estimate customer name.", - "sms_notification.estimate.var.amount": "References to estimate amount.", - "sms_notification.estimate.var.company_name": "References to company name.", - "sms_notification.estimate.var.expiration_date": "References to estimate expirtaion date.", - "sms_notification.estimate.var.estimate_date": "References to estimate date.", - - "sms_notification.customer.var.customer_name": "References to customer name.", - "sms_notification.customer.var.balance": "References to customer outstanding balance.", - "sms_notification.customer.var.company_name": "References to company name.", - - "ability.accounts": "Chart of accounts", - "ability.manual_journal": "Manual journals", - "ability.cashflow": "Cash flow", - "ability.inventory_adjustment": "Inventory adjustments", - "ability.customers": "Customers", - "ability.vendors": "vendors", - "ability.sale_estimates": "Sale estimates", - "ability.sale_invoices": "Sale invoices", - "ability.sale_receipts": "Sale receipts", - "ability.expenses": "Expenses", - "ability.payments_receive": "Payments receive", - "ability.purchase_invoices": "Purchase invoices", - "ability.all_reports": "All reports", - "ability.payments_made": "Payments made", - "ability.preferences": "Preferences", - "ability.mutate_system_preferences": "Mutate the system preferences.", - - "ability.items": "Items", - "ability.view": "View", - "ability.create": "Create", - "ability.edit": "Edit", - "ability.delete": "Delete", - "ability.transactions_locking": "Ability to transactions locking.", - - "ability.balance_sheet_report": "Balance sheet.", - "ability.profit_loss_sheet": "Profit/loss sheet", - "ability.journal": "Journal", - "ability.general_ledger": "General ledger", - "ability.cashflow_report": "Cashflow", - "ability.AR_aging_summary_report": "A/R aging summary", - "ability.AP_aging_summary_report": "A/P aging summary", - "ability.purchases_by_items": "Purchases by items", - "ability.sales_by_items_report": "Sales by items", - "ability.customers_transactions_report": "Customers transactions", - "ability.vendors_transactions_report": "Vendors transactions", - "ability.customers_summary_balance_report": "Customers summary balance", - "ability.vendors_summary_balance_report": "Vendors summary balance", - "ability.inventory_valuation_summary": "Inventory valuation summary", - "ability.inventory_items_details": "Inventory items details", - - "vendor_credit.field.vendor": "Vendor name", - "vendor_credit.field.amount": "Amount", - "vendor_credit.field.currency_code": "Currency code", - "vendor_credit.field.credit_date": "Credit date", - "vendor_credit.field.credit_number": "Credit number", - "vendor_credit.field.note": "Note", - "vendor_credit.field.created_at": "Created at", - "vendor_credit.field.reference_no": "Reference No.", - - "credit_note.field.terms_conditions": "Terms and conditions", - "credit_note.field.note": "Note", - "credit_note.field.currency_code": "Currency code", - "credit_note.field.created_at": "Created at", - "credit_note.field.amount": "Amount", - "credit_note.field.credit_note_number": "Credit note number", - "credit_note.field.credit_note_date": "Credit date", - "credit_note.field.customer": "Customer", - "credit_note.field.reference_no": "Reference No.", - - "Credit note": "Credit note", - "Vendor credit": "Vendor credit", - "Refund credit note": "Refund credit note", - "Refund vendor credit": "Refund vendor credit", - "credit_note.field.status": "Status", - "credit_note.field.status.draft": "Draft", - "credit_note.field.status.published": "Published", - "credit_note.field.status.open": "Open", - "credit_note.field.status.closed": "Closed", - - "transactions_locking.module.sales.label": "Sales", - "transactions_locking.module.purchases.label": "Purchases", - "transactions_locking.module.financial.label": "Financial", - "transactions_locking.module.all_transactions": "All transactions", - - "transactions_locking.module.sales.desc": "Sale invoices, Receipts, credit notes, customers payment receive and customers opening balances.", - "transactions_locking.module.purchases.desc": "Purchase invoices, vendors payments, vendor credit notes and vendors opening balances.", - "transactions_locking.module.financial.desc": "Manual journal, expenses and inventory adjustments.", - - "inventory_adjustment.type.increment": "Increment", - "inventory_adjustment.type.decrement": "Decrement", - - "customer.type.individual": "Individual", - "customer.type.business": "Business", - - "credit_note.view.draft": "Draft", - "credit_note.view.closed": "Closed", - "credit_note.view.open": "Open", - "credit_note.view.published": "Published", - - "vendor_credit.view.draft": "Draft", - "vendor_credit.view.closed": "Closed", - "vendor_credit.view.open": "Open", - "vendor_credit.view.published": "Published", - - "allocation_method.value.label": "Value", - "allocation_method.quantity.label": "Quantity", - - "balance_sheet.assets": "Assets", - "balance_sheet.current_asset": "Current Asset", - "balance_sheet.cash_and_cash_equivalents": "Cash and cash equivalents", - "balance_sheet.accounts_receivable": "Accounts Receivable", - "balance_sheet.inventory": "Inventory", - "balance_sheet.other_current_assets": "Other current assets", - "balance_sheet.fixed_asset": "Fixed Asset", - "balance_sheet.non_current_assets": "Non-Current Assets", - "balance_sheet.liabilities_and_equity": "Liabilities and Equity", - "balance_sheet.liabilities": "Liabilities", - "balance_sheet.current_liabilties": "Current Liabilties", - "balance_sheet.long_term_liabilities": "Long-Term Liabilities", - "balance_sheet.non_current_liabilities": "Non-Current Liabilities", - "balance_sheet.equity": "Equity", - "balance_sheet.net_income": "Net Income", - - "balance_sheet.account_name": "Account name", - "balance_sheet.total": "Total", - "balance_sheet.percentage_of_column": "% of Column", - "balance_sheet.percentage_of_row": "% of Row", - - "financial_sheet.previoud_period_date": "{{date}} (PP)", - "fianncial_sheet.previous_period_change": "Change (PP)", - "financial_sheet.previous_period_percentage": "% Change (PP)", - - "financial_sheet.previous_year_date": "{{date}} (PY)", - "financial_sheet.previous_year_change": "Change (PY)", - "financial_sheet.previous_year_percentage": "% Change (PY)", - "financial_sheet.total_row": "Total {{value}}", - - "profit_loss_sheet.income": "Income", - "profit_loss_sheet.cost_of_sales": "Cost of sales", - "profit_loss_sheet.gross_profit": "GROSS PROFIT", - "profit_loss_sheet.expenses": "Expenses", - "profit_loss_sheet.net_operating_income": "NET OPERATING INCOME", - "profit_loss_sheet.other_income": "Other income", - "profit_loss_sheet.other_expenses": "Other expenses", - "profit_loss_sheet.net_income": "NET INCOME", - - "profit_loss_sheet.account_name": "Account name", - "profit_loss_sheet.total": "Total", - - "profit_loss_sheet.percentage_of_income": "% of Income", - "profit_loss_sheet.percentage_of_expenses": "% of Expenses", - "profit_loss_sheet.percentage_of_column": "% of Column", - "profit_loss_sheet.percentage_of_row": "% of Row", - - "contact_summary_balance.account_name": "Account name", - "contact_summary_balance.total": "Total", - "contact_summary_balance.percentage_column": "% of Column", - - "warehouses.primary_warehouse": "Primary warehouse", - "branches.head_branch": "Head Branch", - - "account.accounts_payable.currency": "Accounts Payable (A/P) - {{currency}}", - "account.accounts_receivable.currency": "Accounts Receivable (A/R) - {{currency}}", - - "role.admin.name": "Admin", - "role.admin.desc": "Unrestricted access to all modules.", - - "role.staff.name": "Staff", - "role.staff.desc": "Access to all modules except reports, settings and accountant.", - - "warehouse_transfer.view.draft.name": "Draft", - "warehouse_transfer.view.in_transit.name": "In Transit", - "warehouse_transfer.view.transferred.name": "Transferred" -} \ No newline at end of file From b167284c8e072ae91e6b5df895e32d24625ead86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 02:58:28 +0200 Subject: [PATCH 08/10] chore(deps): bump axios from 0.20.0 to 1.6.0 in /packages/server (#284) Bumps [axios](https://github.com/axios/axios) from 0.20.0 to 1.6.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.20.0...v1.6.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/server/package-lock.json | 46 +++++++++++++++++++++++-------- packages/server/package.json | 2 +- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/server/package-lock.json b/packages/server/package-lock.json index d420b4941..649c66b6c 100644 --- a/packages/server/package-lock.json +++ b/packages/server/package-lock.json @@ -2083,6 +2083,11 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2643,8 +2648,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "atob": { "version": "2.1.2", @@ -2658,11 +2662,13 @@ "dev": true }, "axios": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", - "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", + "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", "requires": { - "follow-redirects": "^1.10.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "babel-loader": { @@ -3533,7 +3539,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -4230,8 +4235,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "denque": { "version": "1.5.1", @@ -5994,7 +5998,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -11582,8 +11585,27 @@ "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", + "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } }, "source-map-resolve": { "version": "0.5.3", diff --git a/packages/server/package.json b/packages/server/package.json index ed077abae..d364e9b51 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -31,7 +31,7 @@ "agendash": "^3.1.0", "app-root-path": "^3.0.0", "async": "^3.2.0", - "axios": "^0.20.0", + "axios": "^1.6.0", "babel-loader": "^9.1.2", "bcryptjs": "^2.4.3", "bluebird": "^3.7.2", From 151aff4c8e481f286cf1017573c50d8844cc6ec4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 02:58:38 +0200 Subject: [PATCH 09/10] chore(deps): bump axios from 0.20.0 to 1.6.0 (#283) Bumps [axios](https://github.com/axios/axios) from 0.20.0 to 1.6.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.20.0...v1.6.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/webapp/package.json | 2 +- pnpm-lock.yaml | 33 +++++++-------------------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/packages/webapp/package.json b/packages/webapp/package.json index 1d6481add..d4e1c65d1 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -37,7 +37,7 @@ "@typescript-eslint/parser": "^2.10.0", "@welldone-software/why-did-you-render": "^6.0.0-rc.1", "accounting": "^0.4.1", - "axios": "^0.21.2", + "axios": "^1.6.0", "basscss": "^8.0.2", "camelcase": "^5.3.1", "classnames": "^2.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index faa3c040e..625840111 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,8 +66,8 @@ importers: specifier: ^3.2.0 version: 3.2.4 axios: - specifier: ^0.20.0 - version: 0.20.0 + specifier: ^1.6.0 + version: 1.6.0 babel-loader: specifier: ^9.1.2 version: 9.1.2(@babel/core@7.20.12)(webpack@5.76.0) @@ -514,8 +514,8 @@ importers: specifier: ^0.4.1 version: 0.4.1 axios: - specifier: ^0.21.2 - version: 0.21.4 + specifier: ^1.6.0 + version: 1.6.0 basscss: specifier: ^8.0.2 version: 8.1.0 @@ -7819,32 +7819,14 @@ packages: engines: {node: '>=4'} dev: false - /axios@0.20.0: - resolution: {integrity: sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==} - deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 - dependencies: - follow-redirects: 1.15.2 - transitivePeerDependencies: - - debug - dev: false - - /axios@0.21.4: - resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} - dependencies: - follow-redirects: 1.15.2 - transitivePeerDependencies: - - debug - dev: false - - /axios@1.3.2: - resolution: {integrity: sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==} + /axios@1.6.0: + resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==} dependencies: follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - dev: true /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} @@ -12479,7 +12461,6 @@ packages: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true /formidable@1.2.6: resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==} @@ -17856,7 +17837,7 @@ packages: '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.0-rc.38 '@zkochan/js-yaml': 0.0.6 - axios: 1.3.2 + axios: 1.6.0 chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 From d15c5890ede066ee1498bf9a581d1b4a60e2184e Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 28 Nov 2023 19:53:13 +0200 Subject: [PATCH 10/10] feat: export reports csv and xlsx (#286) --- packages/server/package.json | 3 +- .../FinancialStatements/APAgingSummary.ts | 84 ++-- .../FinancialStatements/ARAgingSummary.ts | 76 ++-- .../FinancialStatements/BalanceSheet.ts | 76 ++-- .../FinancialStatements/CashFlow/CashFlow.ts | 108 +++--- .../CustomerBalanceSummary/index.ts | 116 +++--- .../InventoryDetails/index.ts | 113 +++--- .../FinancialStatements/ProfitLossSheet.ts | 81 ++-- .../FinancialStatements/SalesByItems.ts | 15 +- .../SalesTaxLiabilitySummary/index.ts | 83 ++-- .../TransactionsByCustomers/index.ts | 106 +++-- .../TransactionsByVendors/index.ts | 110 +++--- .../FinancialStatements/TrialBalanceSheet.ts | 55 ++- .../VendorBalanceSummary/index.ts | 119 +++--- .../src/interfaces/APAgingSummaryReport.ts | 6 + .../src/interfaces/ARAgingSummaryReport.ts | 6 + .../server/src/interfaces/BalanceSheet.ts | 6 + packages/server/src/interfaces/CashFlow.ts | 7 +- .../src/interfaces/CustomerBalanceSummary.ts | 9 +- packages/server/src/interfaces/Http.ts | 7 + .../server/src/interfaces/InventoryDetails.ts | 17 +- .../server/src/interfaces/ProfitLossSheet.ts | 7 + .../interfaces/SalesTaxLiabilitySummary.ts | 7 + packages/server/src/interfaces/Table.ts | 13 +- .../src/interfaces/TransactionsByCustomers.ts | 6 + .../src/interfaces/TransactionsByVendors.ts | 5 + .../src/interfaces/TrialBalanceSheet.ts | 6 + .../src/interfaces/VendorBalanceSummary.ts | 9 +- packages/server/src/lib/Xlsx/TableSheet.tsx | 134 +++++++ .../AgingSummary/APAgingSummaryApplication.ts | 53 +++ .../APAgingSummaryExportInjectable.ts | 43 +++ .../AgingSummary/APAgingSummaryService.ts | 24 +- .../APAgingSummaryTableInjectable.ts | 36 ++ .../AgingSummary/ARAgingSummaryApplication.ts | 53 +++ .../ARAgingSummaryExportInjectable.ts | 46 +++ .../AgingSummary/ARAgingSummaryService.ts | 18 - .../ARAgingSummaryTableInjectable.ts | 36 ++ .../BalanceSheet/BalanceSheetApplication.ts | 57 +++ .../BalanceSheetExportInjectable.ts | 43 +++ ...etService.ts => BalanceSheetInjectable.ts} | 9 +- .../BalanceSheetTableInjectable.ts | 42 ++ .../CashFlow/CashflowExportInjectable.ts | 46 +++ .../CashFlow/CashflowSheetApplication.ts | 58 +++ .../CashFlow/CashflowTableInjectable.ts | 37 ++ .../CustomerBalanceSummaryApplication.ts | 60 +++ .../CustomerBalanceSummaryExportInjectable.ts | 43 +++ .../CustomerBalanceSummaryService.ts | 29 +- .../CustomerBalanceSummaryTableInjectable.ts | 44 +++ .../CustomerBalanceSummaryTableRows.ts | 2 +- .../FinancialTableStructure.ts | 48 +++ .../InventoryDetails/InventoryDetails.ts | 2 +- .../InventoryDetailsApplication.ts | 66 ++++ .../InventoryDetailsExportInjectable.ts | 43 +++ .../InventoryDetailsService.ts | 4 +- .../InventoryDetails/InventoryDetailsTable.ts | 6 +- .../InventoryDetailsTableInjectable.ts | 45 +++ .../ProfitLossSheetApplication.ts | 60 +++ .../ProfitLossSheetExportInjectable.ts | 43 +++ .../ProfitLossSheet/ProfitLossSheetService.ts | 68 ++-- .../ProfitLossSheetTableInjectable.ts | 42 ++ .../SalesByItems/SalesByItemsService.ts | 4 - .../SalesTaxLiabilitySummaryApplication.ts | 63 +++ ...alesTaxLiabilitySummaryExportInjectable.ts | 46 +++ .../SalesTaxLiabilitySummaryService.ts | 27 -- ...SalesTaxLiabilitySummaryTableInjectable.ts | 40 ++ .../TransactionsByCustomers.ts | 7 - .../TransactionsByCustomersApplication.ts | 72 ++++ ...TransactionsByCustomersExportInjectable.ts | 46 +++ .../TransactionsByCustomersRepository.ts | 6 +- .../TransactionsByCustomersService.ts | 12 +- ...ows.ts => TransactionsByCustomersTable.ts} | 19 +- .../TransactionsByCustomersTableInjectable.ts | 44 +++ .../TransactionsByVendor.ts | 7 - .../TransactionsByVendorApplication.ts | 75 ++++ .../TransactionsByVendorExportInjectable.ts | 46 +++ ...e.ts => TransactionsByVendorInjectable.ts} | 13 +- ...leRows.ts => TransactionsByVendorTable.ts} | 25 +- .../TransactionsByVendorTableInjectable.ts | 44 +++ .../TrialBalanceExportInjectable.ts | 43 +++ .../TrialBalanceSheetApplication.ts | 60 +++ ...vice.ts => TrialBalanceSheetInjectable.ts} | 30 +- .../TrialBalanceSheetTableInjectable.ts | 33 ++ .../VendorBalanceSummary.ts | 4 - .../VendorBalanceSummaryApplication.ts | 62 +++ .../VendorBalanceSummaryExportInjectable.ts | 43 +++ .../VendorBalanceSummaryRepository.ts | 2 +- .../VendorBalanceSummaryService.ts | 20 +- .../VendorBalanceSummaryTableInjectable.ts | 44 +++ .../VendorBalanceSummaryTableRows.ts | 2 +- packages/server/src/utils/deepdash.ts | 22 ++ packages/server/src/utils/table.ts | 4 +- .../APAgingSummaryActionsBar.tsx | 18 +- .../APAgingSummary/APAgingSummaryProvider.tsx | 1 + .../APAgingSummary/components.tsx | 101 ++++- .../ARAgingSummaryActionsBar.tsx | 18 +- .../ARAgingSummary/components.tsx | 102 ++++- .../BalanceSheet/BalanceSheetActionsBar.tsx | 21 +- .../BalanceSheet/components.tsx | 110 +++++- .../CashFlowStatementActionsBar.tsx | 18 +- .../CashFlowStatement/components.tsx | 110 +++++- .../CustomersBalanceSummaryActionsBar.tsx | 20 +- .../CustomersBalanceSummaryProvider.tsx | 1 + .../CustomersBalanceSummaryTable.tsx | 2 +- .../CustomersBalanceSummary/components.tsx | 104 ++++- .../CustomersTransactionsActionsBar.tsx | 20 +- .../CustomersTransactions/components.tsx | 106 ++++- .../InventoryItemDetailsActionsBar.tsx | 18 +- .../InventoryItemDetails/components.tsx | 117 +++++- .../InventoryItemDetails/utils2.tsx | 11 + .../ProfitLossSheet/ProfitLossActionsBar.tsx | 18 +- .../ProfitLossSheet/ProfitLossProvider.tsx | 12 +- .../ProfitLossSheet/components.tsx | 110 +++++- .../SalesTaxLiabilitySummaryActionsBar.tsx | 18 +- .../SalesTaxLiabilitySummary/components.tsx | 109 +++++- .../TrialBalanceActionsBar.tsx | 18 +- .../TrialBalanceSheet/components.tsx | 118 +++++- .../TrialBalanceSheet/utils.tsx | 11 + .../VendorsBalanceSummaryActionsBar.tsx | 18 +- .../VendorsBalanceSummaryTable.tsx | 2 +- .../VendorsBalanceSummary/components.tsx | 96 ++++- .../VendorsTransactionsActionsBar.tsx | 18 +- .../VendorsTransactions/components.tsx | 102 ++++- .../src/hooks/query/financialReports.tsx | 364 +++++++++++++++++- packages/webapp/src/hooks/useDownloadFile.ts | 72 ++++ pnpm-lock.yaml | 63 +++ 125 files changed, 4674 insertions(+), 934 deletions(-) create mode 100644 packages/server/src/interfaces/Http.ts create mode 100644 packages/server/src/lib/Xlsx/TableSheet.tsx create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts rename packages/server/src/services/FinancialStatements/BalanceSheet/{BalanceSheetService.ts => BalanceSheetInjectable.ts} (96%) create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/FinancialTableStructure.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts rename packages/server/src/services/FinancialStatements/TransactionsByCustomer/{TransactionsByCustomersTableRows.ts => TransactionsByCustomersTable.ts} (81%) create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts rename packages/server/src/services/FinancialStatements/TransactionsByVendor/{TransactionsByVendorService.ts => TransactionsByVendorInjectable.ts} (94%) rename packages/server/src/services/FinancialStatements/TransactionsByVendor/{TransactionsByVendorTableRows.ts => TransactionsByVendorTable.ts} (76%) create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts rename packages/server/src/services/FinancialStatements/TrialBalanceSheet/{TrialBalanceSheetService.ts => TrialBalanceSheetInjectable.ts} (78%) create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts create mode 100644 packages/webapp/src/hooks/useDownloadFile.ts diff --git a/packages/server/package.json b/packages/server/package.json index d364e9b51..c72ba7d89 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -100,7 +100,8 @@ "tsyringe": "^4.3.0", "typedi": "^0.8.0", "uniqid": "^5.2.0", - "winston": "^3.2.1" + "winston": "^3.2.1", + "xlsx": "^0.18.5" }, "devDependencies": { "@types/lodash": "^4.14.158", diff --git a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts index b0dc28841..5d626896c 100644 --- a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts @@ -2,19 +2,20 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import APAgingSummaryReportService from '@/services/FinancialStatements/AgingSummary/APAgingSummaryService'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { APAgingSummaryApplication } from '@/services/FinancialStatements/AgingSummary/APAgingSummaryApplication'; export default class APAgingSummaryReportController extends BaseFinancialReportController { @Inject() - APAgingSummaryService: APAgingSummaryReportService; + private APAgingSummaryApp: APAgingSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -28,8 +29,9 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC /** * Validation schema. + * @returns {ValidationChain[]} */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, query('as_date').optional().isISO8601(), @@ -49,42 +51,58 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC } /** - * Retrieve payable aging summary report. + * Retrieves payable aging summary report. + * @param {Request} req - + * @param {Response} res - + * @param {NextFunction} next - */ - async payableAgingSummary(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + private async payableAgingSummary( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.APAgingSummaryApp.table(tenantId, filter); - switch (acceptType) { - case 'application/json+table': - const table = await this.APAgingSummaryService.APAgingSummaryTable( - tenantId, - filter - ); - return res.status(200).send({ - table: { - rows: table.rows, - columns: table.columns, - }, - meta: table.meta, - query: table.query, - }); - break; - default: - const { data, columns, query, meta } = - await this.APAgingSummaryService.APAgingSummary(tenantId, filter); + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const csv = await this.APAgingSummaryApp.csv(tenantId, filter); - return res.status(200).send({ - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }); - break; + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(csv); + // Retrieves the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.APAgingSummaryApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.APAgingSummaryApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts index 489eb04ae..10e42e900 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts @@ -5,16 +5,18 @@ import ARAgingSummaryService from '@/services/FinancialStatements/AgingSummary/A import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ARAgingSummaryApplication } from '@/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class ARAgingSummaryReportController extends BaseFinancialReportController { @Inject() - ARAgingSummaryService: ARAgingSummaryService; + ARAgingSummaryApp: ARAgingSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -30,7 +32,7 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC /** * AR aging summary validation roles. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, @@ -52,41 +54,53 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC /** * Retrieve AR aging summary report. + * @param {Request} req + * @param {Response} res */ - async receivableAgingSummary(req: Request, res: Response) { - const { tenantId, settings } = req; + private async receivableAgingSummary(req: Request, res: Response) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - switch (acceptType) { - case 'application/json+table': - const table = await this.ARAgingSummaryService.ARAgingSummaryTable( - tenantId, - filter - ); - return res.status(200).send({ - table: { - rows: table.rows, - columns: table.columns, - }, - meta: table.meta, - query: table.query, - }); - break; - default: - const { data, columns, query, meta } = - await this.ARAgingSummaryService.ARAgingSummary(tenantId, filter); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.ARAgingSummaryApp.xlsx(tenantId, filter); - return res.status(200).send({ - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }); - break; + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.ARAgingSummaryApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.ARAgingSummaryApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.ARAgingSummaryApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { console.log(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts index bc9499889..0af53d723 100644 --- a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts @@ -3,25 +3,21 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; import { castArray } from 'lodash'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import BalanceSheetStatementService from '@/services/FinancialStatements/BalanceSheet/BalanceSheetService'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import BalanceSheetTable from '@/services/FinancialStatements/BalanceSheet/BalanceSheetTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { BalanceSheetApplication } from '@/services/FinancialStatements/BalanceSheet/BalanceSheetApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class BalanceSheetStatementController extends BaseFinancialReportController { @Inject() - balanceSheetService: BalanceSheetStatementService; - - @Inject() - tenancy: HasTenancyService; + private balanceSheetApp: BalanceSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -38,7 +34,7 @@ export default class BalanceSheetStatementController extends BaseFinancialReport * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get balanceSheetValidationSchema(): ValidationChain[] { + private get balanceSheetValidationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('accounting_method').optional().isIn(['cash', 'accrual']), @@ -84,10 +80,12 @@ export default class BalanceSheetStatementController extends BaseFinancialReport /** * Retrieve the balance sheet. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next */ - async balanceSheet(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; - const i18n = this.tenancy.i18n(tenantId); + private async balanceSheet(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; let filter = this.matchedQueryData(req); @@ -95,29 +93,45 @@ export default class BalanceSheetStatementController extends BaseFinancialReport ...filter, accountsIds: castArray(filter.accountsIds), }; - try { - const { data, columns, query, meta } = - await this.balanceSheetService.balanceSheet(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - const table = new BalanceSheetTable(data, query, i18n); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_CSV, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE == acceptType) { + const table = await this.balanceSheetApp.table(tenantId, filter); - switch (acceptType) { - case 'application/json+table': - return res.status(200).send({ - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - query, - meta, - }); - case 'json': - default: - return res.status(200).send({ data, columns, query, meta }); + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.balanceSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.balanceSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + } else { + const sheet = await this.balanceSheetApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts index df2f3f5dd..bab04246d 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts @@ -8,29 +8,20 @@ import { ValidationChain, } from 'express'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import CashFlowStatementService from '@/services/FinancialStatements/CashFlow/CashFlowService'; -import { - ICashFlowStatementDOO, - ICashFlowStatement, - AbilitySubject, - ReportsAction, -} from '@/interfaces'; -import CashFlowTable from '@/services/FinancialStatements/CashFlow/CashFlowTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { CashflowSheetApplication } from '@/services/FinancialStatements/CashFlow/CashflowSheetApplication'; @Service() export default class CashFlowController extends BaseFinancialReportController { @Inject() - cashFlowService: CashFlowStatementService; - - @Inject() - tenancy: HasTenancyService; + private cashflowSheetApp: CashflowSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -47,7 +38,7 @@ export default class CashFlowController extends BaseFinancialReportController { * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get cashflowValidationSchema(): ValidationChain[] { + private get cashflowValidationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('from_date').optional(), @@ -67,41 +58,6 @@ export default class CashFlowController extends BaseFinancialReportController { ]; } - /** - * Retrieve the cashflow statment to json response. - * @param {ICashFlowStatement} cashFlow - - */ - private transformJsonResponse(cashFlowDOO: ICashFlowStatementDOO) { - const { data, query, meta } = cashFlowDOO; - - return { - data: this.transfromToResponse(data), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }; - } - - /** - * Transformes the report statement to table rows. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToTableRows( - cashFlowDOO: ICashFlowStatementDOO, - tenantId: number - ) { - const i18n = this.tenancy.i18n(tenantId); - const cashFlowTable = new CashFlowTable(cashFlowDOO, i18n); - - return { - table: { - data: cashFlowTable.tableRows(), - columns: cashFlowTable.tableColumns(), - }, - query: this.transfromToResponse(cashFlowDOO.query), - meta: this.transfromToResponse(cashFlowDOO.meta), - }; - } - /** * Retrieve the cash flow statment. * @param {Request} req @@ -109,26 +65,52 @@ export default class CashFlowController extends BaseFinancialReportController { * @param {NextFunction} next * @returns {Response} */ - async cashFlow(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + public async cashFlow(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; const filter = { ...this.matchedQueryData(req), }; try { - const cashFlow = await this.cashFlowService.cashFlow(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(cashFlow, tenantId)); - case 'json': - default: - return res.status(200).send(this.transformJsonResponse(cashFlow)); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.cashflowSheetApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.cashflowSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.status(200).send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.cashflowSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json format. + } else { + const cashflow = await this.cashflowSheetApp.sheet(tenantId, filter); + + return res.status(200).send(cashflow); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts index eb026e752..6c10543f5 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts @@ -1,29 +1,21 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject } from 'typedi'; -import { - AbilitySubject, - ICustomerBalanceSummaryStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import CustomerBalanceSummary from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import CustomerBalanceSummaryTableRows from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { CustomerBalanceSummaryApplication } from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication'; export default class CustomerBalanceSummaryReportController extends BaseFinancialReportController { @Inject() - customerBalanceSummaryService: CustomerBalanceSummary; - - @Inject() - tenancy: HasTenancyService; + private customerBalanceSummaryApp: CustomerBalanceSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -42,7 +34,7 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia /** * Validation schema. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, @@ -62,75 +54,67 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia ]; } - /** - * Transformes the balance summary statement to table rows. - * @param {ICustomerBalanceSummaryStatement} statement - - */ - private transformToTableRows( - tenantId, - { data, query }: ICustomerBalanceSummaryStatement - ) { - const i18n = this.tenancy.i18n(tenantId); - const tableRows = new CustomerBalanceSummaryTableRows(data, query, i18n); - - return { - table: { - columns: tableRows.tableColumns(), - data: tableRows.tableRows(), - }, - query: this.transfromToResponse(query), - }; - } - - /** - * Transformes the balance summary statement to raw json. - * @param {ICustomerBalanceSummaryStatement} customerBalance - - */ - private transformToJsonResponse({ - data, - columns, - query, - }: ICustomerBalanceSummaryStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async customerBalanceSummary( + private async customerBalanceSummary( req: Request, res: Response, next: NextFunction ) { - const { tenantId, settings } = req; + const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const customerBalanceSummary = - await this.customerBalanceSummaryService.customerBalanceSummary( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.customerBalanceSummaryApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.customerBalanceSummaryApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, customerBalanceSummary)); - case 'application/json': - default: - return res - .status(200) - .send(this.transformToJsonResponse(customerBalanceSummary)); + return res.send(buffer); + // Retrieves the json table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.customerBalanceSummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + } else { + const sheet = await this.customerBalanceSummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts index 2f8df7722..07f91af4a 100644 --- a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts @@ -8,24 +8,20 @@ import { ValidationChain, } from 'express'; import BaseController from '@/api/controllers/BaseController'; -import InventoryDetailsService from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsService'; -import InventoryDetailsTable from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; import { AbilitySubject, ReportsAction } from '@/interfaces'; +import { InventortyDetailsApplication } from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class InventoryDetailsController extends BaseController { @Inject() - inventoryDetailsService: InventoryDetailsService; - - @Inject() - tenancy: HasTenancyService; + private inventoryItemDetailsApp: InventortyDetailsApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -45,7 +41,7 @@ export default class InventoryDetailsController extends BaseController { * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ query('number_format.precision') .optional() @@ -77,69 +73,66 @@ export default class InventoryDetailsController extends BaseController { } /** - * Retrieve the cashflow statment to json response. - * @param {ICashFlowStatement} cashFlow - - */ - private transformJsonResponse(inventoryDetails) { - const { data, query, meta } = inventoryDetails; - - return { - data: this.transfromToResponse(data), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }; - } - - /** - * Transformes the report statement to table rows. - */ - private transformToTableRows(inventoryDetails, tenantId: number) { - const i18n = this.tenancy.i18n(tenantId); - const inventoryDetailsTable = new InventoryDetailsTable( - inventoryDetails, - i18n - ); - - return { - table: { - data: inventoryDetailsTable.tableData(), - columns: inventoryDetailsTable.tableColumns(), - }, - query: this.transfromToResponse(inventoryDetails.query), - meta: this.transfromToResponse(inventoryDetails.meta), - }; - } - - /** - * Retrieve the cash flow statment. + * Retrieve the inventory item details sheet. * @param {Request} req * @param {Response} res * @param {NextFunction} next * @returns {Response} */ - async inventoryDetails(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + private async inventoryDetails( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = { ...this.matchedQueryData(req), }; try { - const inventoryDetails = - await this.inventoryDetailsService.inventoryDetails(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.inventoryItemDetailsApp.csv(tenantId, filter); - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(inventoryDetails, tenantId)); - case 'json': - default: - return res - .status(200) - .send(this.transformJsonResponse(inventoryDetails)); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.inventoryItemDetailsApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.inventoryItemDetailsApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + } else { + const sheet = await this.inventoryItemDetailsApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts index 233654dc0..8c2404335 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts @@ -1,24 +1,20 @@ import { Service, Inject } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; -import ProfitLossSheetService from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService'; import BaseFinancialReportController from './BaseFinancialReportController'; import CheckPolicies from '@/api/middleware/CheckPolicies'; import { AbilitySubject, ReportsAction } from '@/interfaces'; -import { ProfitLossSheetTable } from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { ProfitLossSheetApplication } from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication'; @Service() export default class ProfitLossSheetController extends BaseFinancialReportController { @Inject() - profitLossSheetService: ProfitLossSheetService; - - @Inject() - tenancy: HasTenancyService; + private profitLossSheetApp: ProfitLossSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -34,7 +30,7 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('basis').optional(), @@ -85,37 +81,54 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro * @param {Request} req - * @param {Response} res - */ - async profitLossSheet(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; - const i18n = this.tenancy.i18n(tenantId); + private async profitLossSheet( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); + const accept = this.accepts(req); + + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); try { - const { data, query, meta } = - await this.profitLossSheetService.profitLossSheet(tenantId, filter); + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const sheet = await this.profitLossSheetApp.csv(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - switch (acceptType) { - case 'application/json+table': - const table = new ProfitLossSheetTable(data, query, i18n); + return res.send(sheet); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.profitLossSheetApp.table(tenantId, filter); - return res.status(200).send({ - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - query, - meta, - }); - case 'json': - default: - return res.status(200).send({ - data, - query, - meta, - }); + return res.status(200).send(table); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const sheet = await this.profitLossSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(sheet); + // Retrieves the json format. + } else { + const sheet = await this.profitLossSheetApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts index 759165bd1..d31954398 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts @@ -16,15 +16,12 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( '/', - CheckPolicies( - ReportsAction.READ_SALES_BY_ITEMS, - AbilitySubject.Report - ), + CheckPolicies(ReportsAction.READ_SALES_BY_ITEMS, AbilitySubject.Report), this.validationSchema, this.validationResult, asyncMiddleware(this.purchasesByItems.bind(this)) @@ -35,7 +32,7 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ query('from_date').optional().isISO8601(), query('to_date').optional().isISO8601(), @@ -63,7 +60,11 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon * @param {Request} req - * @param {Response} res - */ - async purchasesByItems(req: Request, res: Response, next: NextFunction) { + private async purchasesByItems( + req: Request, + res: Response, + next: NextFunction + ) { const { tenantId } = req; const filter = this.matchedQueryData(req); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts index 56c837288..933b5c9c4 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts @@ -1,20 +1,21 @@ +import { Inject } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; -import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import { SalesTaxLiabilitySummaryService } from '@/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService'; +import { SalesTaxLiabilitySummaryApplication } from '@/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; export default class SalesTaxLiabilitySummary extends BaseFinancialReportController { @Inject() - private salesTaxLiabilitySummaryService: SalesTaxLiabilitySummaryService; + private salesTaxLiabilitySummaryApp: SalesTaxLiabilitySummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -31,8 +32,9 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl /** * Validation schema. + * @returns {ValidationChain[]} */ - get validationSchema() { + private get validationSchema() { return [ query('from_date').optional().isISO8601(), query('to_date').optional().isISO8601(), @@ -45,7 +47,7 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl * @param {Response} res - * @param {NextFunction} next - */ - async salesTaxLiabilitySummary( + private async salesTaxLiabilitySummary( req: Request, res: Response, next: NextFunction @@ -55,33 +57,52 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); - switch (acceptType) { - case 'application/json+table': - const salesTaxLiabilityTable = - await this.salesTaxLiabilitySummaryService.salesTaxLiabilitySummaryTable( - tenantId, - filter - ); + // Retrieves the json table format. + if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.salesTaxLiabilitySummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.salesTaxLiabilitySummaryApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.salesTaxLiabilitySummaryApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - return res.status(200).send({ - table: salesTaxLiabilityTable.table, - query: salesTaxLiabilityTable.query, - meta: salesTaxLiabilityTable.meta, - }); - case 'json': - default: - const salesTaxLiability = - await this.salesTaxLiabilitySummaryService.salesTaxLiability( - tenantId, - filter - ); - return res.status(200).send({ - data: salesTaxLiability.data, - query: salesTaxLiability.query, - meta: salesTaxLiability.meta, - }); + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.salesTaxLiabilitySummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts index fa20ea3f3..4bc3b1f44 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts @@ -1,30 +1,22 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject, Service } from 'typedi'; -import { - AbilitySubject, - ITransactionsByCustomersStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import TransactionsByCustomersService from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService'; -import TransactionsByCustomersTableRows from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { TransactionsByCustomerApplication } from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class TransactionsByCustomersReportController extends BaseFinancialReportController { @Inject() - transactionsByCustomersService: TransactionsByCustomersService; - - @Inject() - tenancy: HasTenancyService; + private transactionsByCustomersApp: TransactionsByCustomerApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -58,45 +50,13 @@ export default class TransactionsByCustomersReportController extends BaseFinanci ]; } - /** - * Transformes the statement to table rows response. - * @param {ITransactionsByCustomersStatement} statement - - */ - private transformToTableResponse(customersTransactions, tenantId) { - const i18n = this.tenancy.i18n(tenantId); - const table = new TransactionsByCustomersTableRows( - customersTransactions, - i18n - ); - return { - table: { - rows: table.tableRows(), - }, - }; - } - - /** - * Transformes the statement to json response. - * @param {ITransactionsByCustomersStatement} statement - - */ - private transfromToJsonResponse( - data, - columns - ): ITransactionsByCustomersStatement { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async transactionsByCustomers( + private async transactionsByCustomers( req: Request, res: Response, next: NextFunction @@ -104,25 +64,51 @@ export default class TransactionsByCustomersReportController extends BaseFinanci const { tenantId } = req; const filter = this.matchedQueryData(req); + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); try { - const report = - await this.transactionsByCustomersService.transactionsByCustomers( + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.transactionsByCustomersApp.table( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + return res.status(200).send(table); + // Retrieve the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const csv = await this.transactionsByCustomersApp.csv(tenantId, filter); - switch (acceptType) { - case 'json': - return res - .status(200) - .send(this.transfromToJsonResponse(report.data, report.columns)); - case 'application/json+table': - default: - return res - .status(200) - .send(this.transformToTableResponse(report.data, tenantId)); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(csv); + // Retrieve the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.transactionsByCustomersApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieve the json format. + } else { + const sheet = await this.transactionsByCustomersApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts index eaf8e6725..a0c1bf037 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts @@ -3,27 +3,19 @@ import { query, ValidationChain } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import TransactionsByVendorsTableRows from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows'; -import TransactionsByVendorsService from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService'; -import { - AbilitySubject, - ITransactionsByVendorsStatement, - ReportsAction, -} from '@/interfaces'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { TransactionsByVendorApplication } from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication'; export default class TransactionsByVendorsReportController extends BaseFinancialReportController { @Inject() - transactionsByVendorsService: TransactionsByVendorsService; - - @Inject() - tenancy: HasTenancyService; + private transactionsByVendorsApp: TransactionsByVendorApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -42,7 +34,7 @@ export default class TransactionsByVendorsReportController extends BaseFinancial /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, @@ -58,64 +50,64 @@ export default class TransactionsByVendorsReportController extends BaseFinancial ]; } - /** - * Transformes the report statement to table rows. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToTableRows(tenantId: number, transactions: any[]) { - const i18n = this.tenancy.i18n(tenantId); - const table = new TransactionsByVendorsTableRows(transactions, i18n); - - return { - table: { - data: table.tableRows(), - }, - }; - } - - /** - * Transformes the report statement to json response. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToJsonResponse({ - data, - columns, - query, - }: ITransactionsByVendorsStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async transactionsByVendors(req: Request, res: Response, next: NextFunction) { + private async transactionsByVendors( + req: Request, + res: Response, + next: NextFunction + ) { const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const report = - await this.transactionsByVendorsService.transactionsByVendors( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.transactionsByVendorsApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, report.data)); - case 'json': - default: - return res.status(200).send(this.transformToJsonResponse(report)); + res.setHeader('Content-Type', 'application/vnd.openxmlformats'); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=report.xlsx' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.transactionsByVendorsApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=report.csv'); + return res.send(buffer); + // Retrieves the json table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.transactionsByVendorsApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the json format. + } else { + const sheet = await this.transactionsByVendorsApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts index da59287e4..ce23c1071 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts @@ -3,15 +3,17 @@ import { Request, Response, Router, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; import { castArray } from 'lodash'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import TrialBalanceSheetService from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService'; +import TrialBalanceSheetService from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { TrialBalanceSheetApplication } from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class TrialBalanceSheetController extends BaseFinancialReportController { @Inject() - trialBalanceSheetService: TrialBalanceSheetService; + private trialBalanceSheetApp: TrialBalanceSheetApplication; /** * Router constructor. @@ -73,21 +75,46 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont }; try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - if (acceptType === 'application/json+table') { - const { table, meta, query } = - await this.trialBalanceSheetService.trialBalanceSheetTable( - tenantId, - filter - ); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves in json table format. + if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const { table, meta, query } = await this.trialBalanceSheetApp.table( + tenantId, + filter + ); return res.status(200).send({ table, meta, query }); + // Retrieves in xlsx format + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.trialBalanceSheetApp.xlsx(tenantId, filter); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves in csv format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.trialBalanceSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves in json format. } else { - const { data, query, meta } = - await this.trialBalanceSheetService.trialBalanceSheet( - tenantId, - filter - ); + const { data, query, meta } = await this.trialBalanceSheetApp.sheet( + tenantId, + filter + ); return res.status(200).send({ data, query, meta }); } } catch (error) { diff --git a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts index e93891938..ade69cb62 100644 --- a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts @@ -3,27 +3,19 @@ import { query } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import VendorBalanceSummaryTableRows from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows'; -import VendorBalanceSummaryService from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService'; -import { - AbilitySubject, - IVendorBalanceSummaryStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { VendorBalanceSummaryApplication } from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication'; export default class VendorBalanceSummaryReportController extends BaseFinancialReportController { @Inject() - vendorBalanceSummaryService: VendorBalanceSummaryService; - - @Inject() - tenancy: HasTenancyService; + private vendorBalanceSummaryApp: VendorBalanceSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -41,7 +33,7 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR /** * Validation schema. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, query('as_date').optional().isISO8601(), @@ -59,73 +51,62 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR ]; } - /** - * Transformes the report statement to table rows. - * @param {IVendorBalanceSummaryStatement} statement - - */ - private transformToTableRows( - tenantId: number, - { data, query }: IVendorBalanceSummaryStatement - ) { - const i18n = this.tenancy.i18n(tenantId); - const tableData = new VendorBalanceSummaryTableRows( - data, - query, - i18n - ); - return { - table: { - columns: tableData.tableColumns(), - data: tableData.tableRows(), - }, - query, - }; - } - - /** - * Transformes the report statement to raw json. - * @param {IVendorBalanceSummaryStatement} statement - - */ - private transformToJsonResponse({ - data, - columns, - }: IVendorBalanceSummaryStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve vendors balance summary. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async vendorBalanceSummary(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + public async vendorBalanceSummary( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const vendorBalanceSummary = - await this.vendorBalanceSummaryService.vendorBalanceSummary( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.vendorBalanceSummaryApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.vendorBalanceSummaryApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, vendorBalanceSummary)); - case 'json': - default: - return res - .status(200) - .send(this.transformToJsonResponse(vendorBalanceSummary)); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader('Content-Type', 'application/vnd.openxmlformats'); + return res.send(buffer); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.vendorBalanceSummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the json format. + } else { + const sheet = await this.vendorBalanceSummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/interfaces/APAgingSummaryReport.ts b/packages/server/src/interfaces/APAgingSummaryReport.ts index db6626167..6bf7c83bb 100644 --- a/packages/server/src/interfaces/APAgingSummaryReport.ts +++ b/packages/server/src/interfaces/APAgingSummaryReport.ts @@ -8,6 +8,7 @@ import { IAgingSummaryData, } from './AgingReport'; import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IAPAgingSummaryQuery extends IAgingSummaryQuery { vendorsIds: number[]; @@ -34,3 +35,8 @@ export interface IAPAgingSummaryMeta { baseCurrency: string; organizationName: string; } + +export interface IAPAgingSummaryTable extends IFinancialTable { + query: IAPAgingSummaryQuery; + meta: IAPAgingSummaryMeta; +} diff --git a/packages/server/src/interfaces/ARAgingSummaryReport.ts b/packages/server/src/interfaces/ARAgingSummaryReport.ts index 7d25e2b2c..d42fc8f7f 100644 --- a/packages/server/src/interfaces/ARAgingSummaryReport.ts +++ b/packages/server/src/interfaces/ARAgingSummaryReport.ts @@ -5,6 +5,7 @@ import { IAgingSummaryContact, IAgingSummaryData, } from './AgingReport'; +import { IFinancialTable } from './Table'; export interface IARAgingSummaryQuery extends IAgingSummaryQuery { customersIds: number[]; @@ -26,3 +27,8 @@ export interface IARAgingSummaryMeta { organizationName: string; baseCurrency: string; } + +export interface IARAgingSummaryTable extends IFinancialTable { + meta: IARAgingSummaryMeta; + query: IARAgingSummaryQuery; +} diff --git a/packages/server/src/interfaces/BalanceSheet.ts b/packages/server/src/interfaces/BalanceSheet.ts index 4dad88e55..a74e48ee8 100644 --- a/packages/server/src/interfaces/BalanceSheet.ts +++ b/packages/server/src/interfaces/BalanceSheet.ts @@ -3,6 +3,7 @@ import { IFormatNumberSettings, IFinancialSheetBranchesQuery, } from './FinancialStatements'; +import { IFinancialTable } from './Table'; // Balance sheet schema nodes types. export enum BALANCE_SHEET_SCHEMA_NODE_TYPE { @@ -215,3 +216,8 @@ export enum IAccountTransactionsGroupBy { Month = 'month', Week = 'week', } + +export interface IBalanceSheetTable extends IFinancialTable { + meta: IBalanceSheetMeta; + query: IBalanceSheetQuery; +} diff --git a/packages/server/src/interfaces/CashFlow.ts b/packages/server/src/interfaces/CashFlow.ts index e9a2dc8cd..1a4a1a6a1 100644 --- a/packages/server/src/interfaces/CashFlow.ts +++ b/packages/server/src/interfaces/CashFlow.ts @@ -1,7 +1,7 @@ import { INumberFormatQuery } from './FinancialStatements'; import { IAccount } from './Account'; import { ILedger } from './Ledger'; -import { ITableRow } from './Table'; +import { IFinancialTable, ITableRow } from './Table'; export interface ICashFlowStatementQuery { fromDate: Date | string; @@ -101,6 +101,11 @@ export interface ICashFlowStatementDOO { query: ICashFlowStatementQuery; } +export interface ICashFlowStatementTable extends IFinancialTable { + meta: ICashFlowStatementMeta; + query: ICashFlowStatementQuery; +} + export interface ICashFlowStatementService { cashFlow( tenantId: number, diff --git a/packages/server/src/interfaces/CustomerBalanceSummary.ts b/packages/server/src/interfaces/CustomerBalanceSummary.ts index cda13f7c9..cf5b5900d 100644 --- a/packages/server/src/interfaces/CustomerBalanceSummary.ts +++ b/packages/server/src/interfaces/CustomerBalanceSummary.ts @@ -1,11 +1,10 @@ -import { INumberFormatQuery } from './FinancialStatements'; - import { IContactBalanceSummaryQuery, IContactBalanceSummaryAmount, IContactBalanceSummaryPercentage, IContactBalanceSummaryTotal, } from './ContactBalanceSummary'; +import { IFinancialTable } from './Table'; export interface ICustomerBalanceSummaryQuery extends IContactBalanceSummaryQuery { @@ -19,7 +18,7 @@ export interface ICustomerBalanceSummaryPercentage extends IContactBalanceSummaryPercentage {} export interface ICustomerBalanceSummaryCustomer { - id: number, + id: number; customerName: string; total: ICustomerBalanceSummaryAmount; percentageOfColumn?: ICustomerBalanceSummaryPercentage; @@ -47,3 +46,7 @@ export interface ICustomerBalanceSummaryService { query: ICustomerBalanceSummaryQuery ): Promise; } + +export interface ICustomerBalanceSummaryTable extends IFinancialTable { + query: ICustomerBalanceSummaryQuery; +} diff --git a/packages/server/src/interfaces/Http.ts b/packages/server/src/interfaces/Http.ts new file mode 100644 index 000000000..2189cb106 --- /dev/null +++ b/packages/server/src/interfaces/Http.ts @@ -0,0 +1,7 @@ +export const ACCEPT_TYPE = { + APPLICATION_PDF: 'application/pdf', + APPLICATION_JSON: 'application/json', + APPLICATION_JSON_TABLE: 'application/json+table', + APPLICATION_XLSX: 'application/xlsx', + APPLICATION_CSV: 'application/csv', +}; diff --git a/packages/server/src/interfaces/InventoryDetails.ts b/packages/server/src/interfaces/InventoryDetails.ts index 733cb588a..033ec269d 100644 --- a/packages/server/src/interfaces/InventoryDetails.ts +++ b/packages/server/src/interfaces/InventoryDetails.ts @@ -1,13 +1,12 @@ -import { - INumberFormatQuery, -} from './FinancialStatements'; +import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IInventoryDetailsQuery { fromDate: Date | string; toDate: Date | string; numberFormat: INumberFormatQuery; noneTransactions: boolean; - itemsIds: number[] + itemsIds: number[]; warehousesIds?: number[]; branchesIds?: number[]; @@ -66,7 +65,7 @@ export interface IInventoryDetailsItemTransaction { cost: IInventoryDetailsNumber; value: IInventoryDetailsNumber; profitMargin: IInventoryDetailsNumber; - + rate: IInventoryDetailsNumber; runningQuantity: IInventoryDetailsNumber; @@ -80,7 +79,6 @@ export type IInventoryDetailsNode = | IInventoryDetailsItemTransaction; export type IInventoryDetailsData = IInventoryDetailsItem[]; - export interface IInventoryItemDetailMeta { isCostComputeRunning: boolean; organizationName: string; @@ -91,4 +89,9 @@ export interface IInvetoryItemDetailDOO { data: IInventoryDetailsData; query: IInventoryDetailsQuery; meta: IInventoryItemDetailMeta; -} \ No newline at end of file +} + +export interface IInvetoryItemDetailsTable extends IFinancialTable { + query: IInventoryDetailsQuery; + meta: IInventoryItemDetailMeta; +} diff --git a/packages/server/src/interfaces/ProfitLossSheet.ts b/packages/server/src/interfaces/ProfitLossSheet.ts index 4f2eec656..944a0a950 100644 --- a/packages/server/src/interfaces/ProfitLossSheet.ts +++ b/packages/server/src/interfaces/ProfitLossSheet.ts @@ -2,6 +2,7 @@ import { IFinancialSheetBranchesQuery, INumberFormatQuery, } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export enum ProfitLossAggregateNodeId { INCOME = 'INCOME', @@ -177,3 +178,9 @@ export enum ProfitLossSheetRowType { ACCOUNT = 'ACCOUNT', TOTAL = 'TOTAL', } + + +export interface IProfitLossSheetTable extends IFinancialTable{ + meta: IProfitLossSheetMeta; + query: IProfitLossSheetQuery; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts index 8b04c9719..2fbc9f13d 100644 --- a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts +++ b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts @@ -1,3 +1,5 @@ +import { IFinancialTable } from "./Table"; + export interface SalesTaxLiabilitySummaryQuery { fromDate: Date; toDate: Date; @@ -49,3 +51,8 @@ export interface SalesTaxLiabilitySummaryMeta { organizationName: string; baseCurrency: string; } + +export interface ISalesTaxLiabilitySummaryTable extends IFinancialTable { + query: SalesTaxLiabilitySummaryQuery; + meta: SalesTaxLiabilitySummaryMeta; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/Table.ts b/packages/server/src/interfaces/Table.ts index 28ff72f5c..a567d2d92 100644 --- a/packages/server/src/interfaces/Table.ts +++ b/packages/server/src/interfaces/Table.ts @@ -10,7 +10,7 @@ export interface ITableCell { } export type ITableRow = { - rows: ITableCell[]; + cells: ITableCell[]; }; export interface ITableColumn { @@ -28,4 +28,13 @@ export interface ITable { export interface ITableColumnAccessor { key: string; accessor: string; -} \ No newline at end of file +} + +export interface ITableData { + columns: ITableColumn[]; + rows: ITableRow[]; +} + +export interface IFinancialTable { + table: ITableData; +} diff --git a/packages/server/src/interfaces/TransactionsByCustomers.ts b/packages/server/src/interfaces/TransactionsByCustomers.ts index fe2fbf5e2..fcfb01ea6 100644 --- a/packages/server/src/interfaces/TransactionsByCustomers.ts +++ b/packages/server/src/interfaces/TransactionsByCustomers.ts @@ -1,3 +1,4 @@ +import { IFinancialTable, ITableData } from './Table'; import { ITransactionsByContactsAmount, ITransactionsByContactsTransaction, @@ -26,6 +27,11 @@ export type ITransactionsByCustomersData = ITransactionsByCustomersCustomer[]; export interface ITransactionsByCustomersStatement { data: ITransactionsByCustomersData; + query: ITransactionsByCustomersFilter; +} + +export interface ITransactionsByCustomersTable extends IFinancialTable { + query: ITransactionsByCustomersFilter; } export interface ITransactionsByCustomersService { diff --git a/packages/server/src/interfaces/TransactionsByVendors.ts b/packages/server/src/interfaces/TransactionsByVendors.ts index 107c7662e..ae129bc79 100644 --- a/packages/server/src/interfaces/TransactionsByVendors.ts +++ b/packages/server/src/interfaces/TransactionsByVendors.ts @@ -1,3 +1,4 @@ +import { IFinancialTable } from './Table'; import { ITransactionsByContactsAmount, ITransactionsByContactsTransaction, @@ -34,3 +35,7 @@ export interface ITransactionsByVendorsService { filter: ITransactionsByVendorsFilter ): Promise; } + +export interface ITransactionsByVendorTable extends IFinancialTable { + query: ITransactionsByVendorsFilter; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/TrialBalanceSheet.ts b/packages/server/src/interfaces/TrialBalanceSheet.ts index 56f13e7fa..f423503ae 100644 --- a/packages/server/src/interfaces/TrialBalanceSheet.ts +++ b/packages/server/src/interfaces/TrialBalanceSheet.ts @@ -1,4 +1,5 @@ import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface ITrialBalanceSheetQuery { fromDate: Date | string; @@ -48,3 +49,8 @@ export interface ITrialBalanceStatement { query: ITrialBalanceSheetQuery; meta: ITrialBalanceSheetMeta; } + +export interface ITrialBalanceSheetTable extends IFinancialTable { + meta: ITrialBalanceSheetMeta; + query: ITrialBalanceSheetQuery; +} diff --git a/packages/server/src/interfaces/VendorBalanceSummary.ts b/packages/server/src/interfaces/VendorBalanceSummary.ts index af75b2d67..d214202df 100644 --- a/packages/server/src/interfaces/VendorBalanceSummary.ts +++ b/packages/server/src/interfaces/VendorBalanceSummary.ts @@ -1,8 +1,9 @@ import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IVendorBalanceSummaryQuery { asDate: Date; - vendorsIds: number[], + vendorsIds: number[]; numberFormat: INumberFormatQuery; percentageColumn: boolean; noneTransactions: boolean; @@ -45,6 +46,10 @@ export interface IVendorBalanceSummaryStatement { export interface IVendorBalanceSummaryService { vendorBalanceSummary( tenantId: number, - query: IVendorBalanceSummaryQuery, + query: IVendorBalanceSummaryQuery ): Promise; } + +export interface IVendorBalanceSummaryTable extends IFinancialTable { + query: IVendorBalanceSummaryQuery; +} diff --git a/packages/server/src/lib/Xlsx/TableSheet.tsx b/packages/server/src/lib/Xlsx/TableSheet.tsx new file mode 100644 index 000000000..5bffd1bcf --- /dev/null +++ b/packages/server/src/lib/Xlsx/TableSheet.tsx @@ -0,0 +1,134 @@ +import xlsx, { WorkBook } from 'xlsx'; +import { IFinancialTable, ITableData } from '@/interfaces'; +import { FinancialTableStructure } from '@/services/FinancialStatements/FinancialTableStructure'; + +interface ITableSheet { + convertToXLSX(): WorkBook; + convertToCSV(): string; + convertToBuffer(workbook: WorkBook, fileType: string): Buffer; +} + +export class TableSheet implements ITableSheet { + private table: ITableData; + + constructor(table: ITableData) { + this.table = table; + } + + /** + * Retrieves the columns labels. + * @returns {string[]} + */ + private get columns() { + return this.table.columns.map((col) => col.label); + } + + /** + * Retrieves the columns accessors. + * @returns {string[]} + */ + private get columnsAccessors() { + return this.table.columns.map((col, index) => { + return `${index}`; + }); + } + + /** + * Retrieves the rows data cellIndex/Value. + * @returns {Record} + */ + private get rows() { + const computedRows = FinancialTableStructure.flatNestedTree( + this.table.rows + ); + return computedRows.map((row) => { + const entries = row.cells.map((cell, index) => { + return [`${index}`, cell.value]; + }); + return Object.fromEntries(entries); + }); + } + + /** + * Converts the table to a CSV string. + * @returns {string} + */ + public convertToCSV(): string { + // Define custom headers + const headers = this.columns; + + // Convert data to worksheet with headers + const worksheet = xlsx.utils.json_to_sheet(this.rows, { + header: this.columnsAccessors, + }); + // Add custom headers to the worksheet + xlsx.utils.sheet_add_aoa(worksheet, [headers], { origin: 'A1' }); + + // Convert worksheet to CSV format + const csvOutput = xlsx.utils.sheet_to_csv(worksheet); + + return csvOutput; + } + + /** + * Convert the array of objects to an XLSX file with styled headers + * @returns {Workbook} + */ + public convertToXLSX(): WorkBook { + // Create a new workbook and a worksheet + const workbook = xlsx.utils.book_new(); + const worksheet = xlsx.utils.json_to_sheet(this.rows, { + header: this.columnsAccessors, + }); + // Add custom headers to the worksheet + xlsx.utils.sheet_add_aoa(worksheet, [this.columns], { + origin: 'A1', + }); + // Adjust column width. + worksheet['!cols'] = this.computeXlsxColumnsWidths(this.rows); + + // Append the worksheet to the workbook + xlsx.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + + return workbook; + } + + /** + * Converts the given workbook to buffer of the given file type + * @param {WorkBook} workbook + * @param {string} fileType + * @returns {Promise} + */ + public convertToBuffer(workbook: WorkBook, fileType: 'xlsx' | 'csv'): Buffer { + return xlsx.write(workbook, { + type: 'buffer', + bookType: fileType, + cellStyles: true, + }); + } + + /** + * Adjusts and computes the columns width. + * @param {} rows + * @returns {{wch: number}[]} + */ + private computeXlsxColumnsWidths = (rows): { wch: number }[] => { + const cols = [{ wch: 60 }]; + + this.columns.map((column) => { + cols.push({ wch: column.length }); + }); + rows.forEach((row) => { + const entries = Object.entries(row); + + entries.forEach(([key, value]) => { + if (cols[key]) { + cols[key].wch = Math.max(cols[key].wch, String(value).length); + } else { + cols[key] = { wch: String(value).length }; + } + }); + }); + return cols; + }; +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts new file mode 100644 index 000000000..73c08b2d8 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts @@ -0,0 +1,53 @@ +import { Inject, Service } from 'typedi'; +import { APAgingSummaryExportInjectable } from './APAgingSummaryExportInjectable'; +import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; +import { IAPAgingSummaryQuery } from '@/interfaces'; +import { APAgingSummaryService } from './APAgingSummaryService'; + +@Service() +export class APAgingSummaryApplication { + @Inject() + private APAgingSummaryTable: APAgingSummaryTableInjectable; + + @Inject() + private APAgingSummaryExport: APAgingSummaryExportInjectable; + + @Inject() + private APAgingSummarySheet: APAgingSummaryService; + + /** + * Retrieve the A/P aging summary in sheet format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public sheet(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummarySheet.APAgingSummary(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public table(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryTable.table(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public csv(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryExport.csv(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public xlsx(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts new file mode 100644 index 000000000..4561687e7 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { IAPAgingSummaryQuery } from '@/interfaces'; + +@Service() +export class APAgingSummaryExportInjectable { + @Inject() + private APAgingSummaryTable: APAgingSummaryTableInjectable; + + /** + * Retrieves the A/P aging summary sheet in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IAPAgingSummaryQuery) { + const table = await this.APAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the A/P aging summary sheet in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { + const table = await this.APAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts index 73860c9a5..fa3e6a2b3 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts @@ -1,14 +1,13 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; +import { isEmpty } from 'lodash'; import { IAPAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import APAgingSummarySheet from './APAgingSummarySheet'; import { Tenant } from '@/system/models'; -import { isEmpty } from 'lodash'; -import APAgingSummaryTable from './APAgingSummaryTable'; @Service() -export default class PayableAgingSummaryService { +export class APAgingSummaryService { @Inject() tenancy: TenancyService; @@ -18,7 +17,7 @@ export default class PayableAgingSummaryService { /** * Default report query. */ - get defaultQuery(): IAPAgingSummaryQuery { + private get defaultQuery(): IAPAgingSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), agingDaysBefore: 30, @@ -119,21 +118,4 @@ export default class PayableAgingSummaryService { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves A/P aging summary in table format. - * @param {number} tenantId - * @param {IAPAgingSummaryQuery} query - */ - async APAgingSummaryTable(tenantId: number, query: IAPAgingSummaryQuery) { - const report = await this.APAgingSummary(tenantId, query); - const table = new APAgingSummaryTable(report.data, query, {}); - - return { - columns: table.tableColumns(), - rows: table.tableRows(), - meta: report.meta, - query: report.query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts new file mode 100644 index 000000000..f9eda1613 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from 'typedi'; +import { IAPAgingSummaryQuery, IAPAgingSummaryTable } from '@/interfaces'; +import { APAgingSummaryService } from './APAgingSummaryService'; +import APAgingSummaryTable from './APAgingSummaryTable'; + +@Service() +export class APAgingSummaryTableInjectable { + @Inject() + private APAgingSummarySheet: APAgingSummaryService; + + /** + * Retrieves A/P aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { + const report = await this.APAgingSummarySheet.APAgingSummary( + tenantId, + query + ); + const table = new APAgingSummaryTable(report.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: report.meta, + query: report.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts new file mode 100644 index 000000000..d3282ca4b --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts @@ -0,0 +1,53 @@ +import { Inject, Service } from 'typedi'; +import { IARAgingSummaryQuery } from '@/interfaces'; +import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; +import { ARAgingSummaryExportInjectable } from './ARAgingSummaryExportInjectable'; +import ARAgingSummaryService from './ARAgingSummaryService'; + +@Service() +export class ARAgingSummaryApplication { + @Inject() + private ARAgingSummaryTable: ARAgingSummaryTableInjectable; + + @Inject() + private ARAgingSummaryExport: ARAgingSummaryExportInjectable; + + @Inject() + private ARAgingSummarySheet: ARAgingSummaryService; + + /** + * Retrieve the A/R aging summary sheet. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public sheet(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummarySheet.ARAgingSummary(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public table(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryTable.table(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public xlsx(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public csv(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts new file mode 100644 index 000000000..25c3dd064 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; +import { IARAgingSummaryQuery } from '@/interfaces'; + +@Service() +export class ARAgingSummaryExportInjectable { + @Inject() + private ARAgingSummaryTable: ARAgingSummaryTableInjectable; + + /** + * Retrieves the A/R aging summary sheet in XLSX format. + * @param {number} tenantId + * @param {IARAgingSummaryQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const table = await this.ARAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the A/R aging summary sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const table = await this.ARAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts index 60bdb8675..e13dfc276 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts @@ -5,7 +5,6 @@ import { IARAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import ARAgingSummarySheet from './ARAgingSummarySheet'; import { Tenant } from '@/system/models'; -import ARAgingSummaryTable from './ARAgingSummaryTable'; @Service() export default class ARAgingSummaryService { @@ -118,21 +117,4 @@ export default class ARAgingSummaryService { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves A/R aging summary in table format. - * @param {number} tenantId - * @param {IARAgingSummaryQuery} query - */ - async ARAgingSummaryTable(tenantId: number, query: IARAgingSummaryQuery) { - const report = await this.ARAgingSummary(tenantId, query); - const table = new ARAgingSummaryTable(report.data, query, {}); - - return { - columns: table.tableColumns(), - rows: table.tableRows(), - meta: report.meta, - query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts new file mode 100644 index 000000000..10ac9ee8c --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts @@ -0,0 +1,36 @@ +import { IARAgingSummaryQuery, IARAgingSummaryTable } from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import ARAgingSummaryTable from './ARAgingSummaryTable'; +import ARAgingSummaryService from './ARAgingSummaryService'; + +@Service() +export class ARAgingSummaryTableInjectable { + @Inject() + private ARAgingSummarySheet: ARAgingSummaryService; + + /** + * Retrieves A/R aging summary in table format. + * @param {number} tenantId + * @param {IARAgingSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const report = await this.ARAgingSummarySheet.ARAgingSummary( + tenantId, + query + ); + const table = new ARAgingSummaryTable(report.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: report.meta, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts new file mode 100644 index 000000000..01ab77bfe --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts @@ -0,0 +1,57 @@ +import { Inject, Service } from 'typedi'; +import { IBalanceSheetQuery } from '@/interfaces'; +import { BalanceSheetExportInjectable } from './BalanceSheetExportInjectable'; +import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; +import BalanceSheetStatementService from './BalanceSheetInjectable'; + +@Service() +export class BalanceSheetApplication { + @Inject() + public balanceSheetExport: BalanceSheetExportInjectable; + + @Inject() + public balanceSheetTable: BalanceSheetTableInjectable; + + @Inject() + public balanceSheet: BalanceSheetStatementService; + + /** + * Retrieves the balnace sheet in json format. + * @param {numnber} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheet.balanceSheet(tenantId, query); + } + + /** + * Retrieves the balance sheet in table format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheetTable.table(tenantId, query); + } + + /** + * Retrieves the balance sheet in XLSX format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheetExport.xlsx(tenantId, query); + } + + /** + * Retrieves the balance sheet in CSV format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IBalanceSheetQuery): Promise { + return this.balanceSheetExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts new file mode 100644 index 000000000..2c43d5f80 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { IBalanceSheetQuery } from '@/interfaces'; + +@Service() +export class BalanceSheetExportInjectable { + @Inject() + private balanceSheetTable: BalanceSheetTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IBalanceSheetQuery) { + const table = await this.balanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IBalanceSheetQuery + ): Promise { + const table = await this.balanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts similarity index 96% rename from packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts rename to packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts index b0470c745..02e136ca1 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts @@ -19,13 +19,10 @@ export default class BalanceSheetStatementService implements IBalanceSheetStatementService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; + private inventoryService: InventoryService; /** * Defaults balance sheet filter query. @@ -94,10 +91,8 @@ export default class BalanceSheetStatementService /** * Retrieve balance sheet statement. - * ------------- * @param {number} tenantId * @param {IBalanceSheetQuery} query - * * @return {IBalanceSheetStatement} */ public async balanceSheet( diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts new file mode 100644 index 000000000..3eb769350 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts @@ -0,0 +1,42 @@ +import { Inject, Service } from 'typedi'; +import BalanceSheetStatementService from './BalanceSheetInjectable'; +import BalanceSheetTable from './BalanceSheetTable'; +import { IBalanceSheetQuery, IBalanceSheetTable } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; + +@Service() +export class BalanceSheetTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private balanceSheetService: BalanceSheetStatementService; + + /** + * Retrieves the balance sheet in table format. + * @param {number} tenantId + * @param {number} query + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: IBalanceSheetQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data, query, meta } = await this.balanceSheetService.balanceSheet( + tenantId, + filter + ); + const table = new BalanceSheetTable(data, query, i18n); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + query, + meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts new file mode 100644 index 000000000..8562cfbf5 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ICashFlowStatementQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; + +@Service() +export class CashflowExportInjectable { + @Inject() + private cashflowSheetTable: CashflowTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const table = await this.cashflowSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const table = await this.cashflowSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts new file mode 100644 index 000000000..0fd8b7357 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts @@ -0,0 +1,58 @@ +import { Inject, Service } from 'typedi'; +import { CashflowExportInjectable } from './CashflowExportInjectable'; +import { ICashFlowStatementQuery } from '@/interfaces'; +import CashFlowStatementService from './CashFlowService'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; + +@Service() +export class CashflowSheetApplication { + @Inject() + private cashflowExport: CashflowExportInjectable; + + @Inject() + private cashflowSheet: CashFlowStatementService; + + @Inject() + private cashflowTable: CashflowTableInjectable; + + /** + * Retrieves the cashflow sheet + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + */ + public async sheet(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowSheet.cashFlow(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in table format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + */ + public async table(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowTable.table(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowExport.xlsx(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + return this.cashflowExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts new file mode 100644 index 000000000..0a54071f2 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts @@ -0,0 +1,37 @@ +import { Inject, Service } from "typedi"; +import { ICashFlowStatementQuery, ICashFlowStatementTable } from "@/interfaces"; +import HasTenancyService from "@/services/Tenancy/TenancyService"; +import CashFlowTable from "./CashFlowTable"; +import CashFlowStatementService from "./CashFlowService"; + +@Service() +export class CashflowTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private cashflowSheet: CashFlowStatementService; + + /** + * Retrieves the cash flow table. + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const cashflowDOO = await this.cashflowSheet.cashFlow(tenantId, query); + const cashflowTable = new CashFlowTable(cashflowDOO, i18n); + + return { + table: { + columns: cashflowTable.tableColumns(), + rows: cashflowTable.tableRows(), + }, + query: cashflowDOO.query, + meta: cashflowDOO.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts new file mode 100644 index 000000000..964cd91a9 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { CustomerBalanceSummaryExportInjectable } from './CustomerBalanceSummaryExportInjectable'; +import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; +import { ICustomerBalanceSummaryQuery } from '@/interfaces'; +import { CustomerBalanceSummaryService } from './CustomerBalanceSummaryService'; + +@Service() +export class CustomerBalanceSummaryApplication { + @Inject() + private customerBalanceSummaryTable: CustomerBalanceSummaryTableInjectable; + + @Inject() + private customerBalanceSummaryExport: CustomerBalanceSummaryExportInjectable; + + @Inject() + private customerBalanceSummarySheet: CustomerBalanceSummaryService; + + /** + * Retrieves the customer balance sheet in json format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummarySheet.customerBalanceSummary( + tenantId, + query + ); + } + + /** + * Retrieves the customer balance sheet in json format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryTable.table(tenantId, query); + } + + /** + * Retrieves the customer balance sheet in XLSX format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieves the customer balance sheet in CSV format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts new file mode 100644 index 000000000..97fec14d8 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { ICustomerBalanceSummaryQuery } from '@/interfaces'; +import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; + +@Service() +export class CustomerBalanceSummaryExportInjectable { + @Inject() + private customerBalanceSummaryTable: CustomerBalanceSummaryTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ICustomerBalanceSummaryQuery) { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICustomerBalanceSummaryQuery + ): Promise { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts index 01ec0e050..78afc3bb2 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts @@ -1,7 +1,5 @@ import { Inject } from 'typedi'; import moment from 'moment'; -import { isEmpty, map } from 'lodash'; -import TenancyService from '@/services/Tenancy/TenancyService'; import * as R from 'ramda'; import { ICustomerBalanceSummaryService, @@ -11,28 +9,21 @@ import { ILedgerEntry, } from '@/interfaces'; import { CustomerBalanceSummaryReport } from './CustomerBalanceSummary'; - import Ledger from '@/services/Accounting/Ledger'; import CustomerBalanceSummaryRepository from './CustomerBalanceSummaryRepository'; import { Tenant } from '@/system/models'; -export default class CustomerBalanceSummaryService +export class CustomerBalanceSummaryService implements ICustomerBalanceSummaryService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; - - @Inject() - reportRepository: CustomerBalanceSummaryRepository; + private reportRepository: CustomerBalanceSummaryRepository; /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} */ - get defaultQuery(): ICustomerBalanceSummaryQuery { + private get defaultQuery(): ICustomerBalanceSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), numberFormat: { @@ -43,13 +34,12 @@ export default class CustomerBalanceSummaryService negativeFormat: 'mines', }, percentageColumn: false, - + noneZero: false, noneTransactions: true, }; } - /** * Retrieve the customers ledger entries mapped from accounts transactions. * @param {number} tenantId @@ -75,7 +65,7 @@ export default class CustomerBalanceSummaryService * @param {ICustomerBalanceSummaryQuery} query * @return {Promise} */ - async customerBalanceSummary( + public async customerBalanceSummary( tenantId: number, query: ICustomerBalanceSummaryQuery ): Promise { @@ -86,13 +76,6 @@ export default class CustomerBalanceSummaryService // Merges the default query and request query. const filter = { ...this.defaultQuery, ...query }; - this.logger.info( - '[customer_balance_summary] trying to calculate the report.', - { - filter, - tenantId, - } - ); // Retrieve the customers list ordered by the display name. const customers = await this.reportRepository.getCustomers( tenantId, @@ -111,7 +94,7 @@ export default class CustomerBalanceSummaryService ledger, customers, filter, - tenant.metadata.baseCurrency, + tenant.metadata.baseCurrency ); return { diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts new file mode 100644 index 000000000..56450d4ca --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import { CustomerBalanceSummaryService } from './CustomerBalanceSummaryService'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { + ICustomerBalanceSummaryQuery, + ICustomerBalanceSummaryTable, +} from '@/interfaces'; +import { CustomerBalanceSummaryTable } from './CustomerBalanceSummaryTableRows'; + +@Service() +export class CustomerBalanceSummaryTableInjectable { + @Inject() + private customerBalanceSummaryService: CustomerBalanceSummaryService; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the customer balance sheet in table format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: ICustomerBalanceSummaryQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + const { data, query } = + await this.customerBalanceSummaryService.customerBalanceSummary( + tenantId, + filter + ); + const tableRows = new CustomerBalanceSummaryTable(data, filter, i18n); + + return { + table: { + columns: tableRows.tableColumns(), + rows: tableRows.tableRows(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts index b55a12613..e6cdc6415 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts @@ -15,7 +15,7 @@ enum TABLE_ROWS_TYPES { TOTAL = 'TOTAL', } -export default class CustomerBalanceSummaryTable { +export class CustomerBalanceSummaryTable { report: ICustomerBalanceSummaryData; query: ICustomerBalanceSummaryQuery; i18n: any; diff --git a/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts b/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts new file mode 100644 index 000000000..6b3bb38b7 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts @@ -0,0 +1,48 @@ +import { ITableRow } from '@/interfaces'; +import { flatNestedTree } from '@/utils/deepdash'; +import { repeat } from 'lodash'; + +interface FlatNestTreeOpts { + nestedPrefix?: string; + nestedPrefixIndex?: number; +} + +export class FinancialTableStructure { + /** + * Converts the given table object with nested rows in flat rows. + * @param {ITableRow[]} + * @param {FlatNestTreeOpts} + * @returns {ITableRow[]} + */ + public static flatNestedTree = ( + obj: ITableRow[], + options?: FlatNestTreeOpts + ): ITableRow[] => { + const parsedOptions = { + nestedPrefix: ' ', + nestedPrefixIndex: 0, + ...options, + }; + const { nestedPrefixIndex, nestedPrefix } = parsedOptions; + + return flatNestedTree( + obj, + (item, key, context) => { + const cells = item.cells.map((cell, index) => { + return { + ...cell, + value: + (context.depth > 1 && nestedPrefixIndex === index + ? repeat(nestedPrefix, context.depth) + : '') + cell.value, + }; + }); + return { + ...item, + cells, + }; + }, + parsedOptions + ); + }; +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts index d09cf19cd..489acff3e 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts @@ -29,7 +29,7 @@ enum INodeTypes { CLOSING_ENTRY = 'CLOSING_ENTRY', } -export default class InventoryDetails extends FinancialSheet { +export class InventoryDetails extends FinancialSheet { readonly inventoryTransactionsByItemId: Map; readonly openingBalanceTransactions: Map; readonly query: IInventoryDetailsQuery; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts new file mode 100644 index 000000000..a2639094e --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts @@ -0,0 +1,66 @@ +import { + IInventoryDetailsQuery, + IInvetoryItemDetailsTable, +} from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import { InventoryDetailsExportInjectable } from './InventoryDetailsExportInjectable'; +import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; +import { InventoryDetailsService } from './InventoryDetailsService'; + +@Service() +export class InventortyDetailsApplication { + @Inject() + private inventoryDetailsExport: InventoryDetailsExportInjectable; + + @Inject() + private inventoryDetailsTable: InventoryDetailsTableInjectable; + + @Inject() + private inventoryDetails: InventoryDetailsService; + + /** + * Retrieves the inventory details report in sheet format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: IInventoryDetailsQuery) { + return this.inventoryDetails.inventoryDetails(tenantId, query); + } + + /** + * Retrieve the inventory details report in table format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns + */ + public table( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + return this.inventoryDetailsTable.table(tenantId, query); + } + + /** + * Retrieves the inventory details report in XLSX format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + return this.inventoryDetailsExport.xlsx(tenantId, query); + } + + /** + * Retrieves the inventory details report in CSV format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IInventoryDetailsQuery): Promise { + return this.inventoryDetailsExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts new file mode 100644 index 000000000..bede24eb4 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IInventoryDetailsQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; + +@Service() +export class InventoryDetailsExportInjectable { + @Inject() + private inventoryDetailsTable: InventoryDetailsTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IInventoryDetailsQuery) { + const table = await this.inventoryDetailsTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const table = await this.inventoryDetailsTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts index cdeca4f39..d74137753 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts @@ -6,7 +6,7 @@ import { IInventoryItemDetailMeta, } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; -import InventoryDetails from './InventoryDetails'; +import { InventoryDetails } from './InventoryDetails'; import FinancialSheet from '../FinancialSheet'; import InventoryDetailsRepository from './InventoryDetailsRepository'; import InventoryService from '@/services/Inventory/Inventory'; @@ -14,7 +14,7 @@ import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; @Service() -export default class InventoryDetailsService extends FinancialSheet { +export class InventoryDetailsService extends FinancialSheet { @Inject() private tenancy: TenancyService; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts index 98d5522f2..1fa6d602d 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts @@ -20,13 +20,13 @@ enum IROW_TYPE { const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; -export default class InventoryDetailsTable { +export class InventoryDetailsTable { i18n: any; report: any; /** * Constructor method. - * @param {ICashFlowStatement} reportStatement - Report statement. + * @param {ICashFlowStatement} report - Report statement. */ constructor(reportStatement, i18n) { this.report = reportStatement; @@ -172,7 +172,7 @@ export default class InventoryDetailsTable { * Retrieve the table rows of the inventory item details. * @returns {ITableRow[]} */ - public tableData = (): ITableRow[] => { + public tableRows = (): ITableRow[] => { return this.itemsMapper(this.report.data); }; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts new file mode 100644 index 000000000..7cf803b46 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts @@ -0,0 +1,45 @@ +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { Inject, Service } from 'typedi'; +import { InventoryDetailsTable } from './InventoryDetailsTable'; +import { + IInventoryDetailsQuery, + IInvetoryItemDetailsTable, +} from '@/interfaces'; +import { InventoryDetailsService } from './InventoryDetailsService'; + +@Service() +export class InventoryDetailsTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private inventoryDetails: InventoryDetailsService; + + /** + * Retrieves the inventory item details in table format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const inventoryDetails = await this.inventoryDetails.inventoryDetails( + tenantId, + query + ); + const table = new InventoryDetailsTable(inventoryDetails, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: inventoryDetails.query, + meta: inventoryDetails.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts new file mode 100644 index 000000000..eee89e73a --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { ProfitLossSheetExportInjectable } from './ProfitLossSheetExportInjectable'; +import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; +import { IProfitLossSheetQuery, IProfitLossSheetTable } from '@/interfaces'; +import ProfitLossSheetService from './ProfitLossSheetService'; + +@Service() +export class ProfitLossSheetApplication { + @Inject() + private profitLossTable: ProfitLossSheetTableInjectable; + + @Inject() + private profitLossExport: ProfitLossSheetExportInjectable; + + @Inject() + private profitLossSheet: ProfitLossSheetService; + + /** + * Retreives the profit/loss sheet. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {} + */ + public sheet(tenantId: number, query: IProfitLossSheetQuery) { + return this.profitLossSheet.profitLossSheet(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet table format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public table( + tenantId: number, + query: IProfitLossSheetQuery + ): Promise { + return this.profitLossTable.table(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet in csv format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IProfitLossSheetQuery): Promise { + return this.profitLossExport.csv(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet in xlsx format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: IProfitLossSheetQuery): Promise { + return this.profitLossExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts new file mode 100644 index 000000000..ba2371797 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IProfitLossSheetQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; + +@Service() +export class ProfitLossSheetExportInjectable { + @Inject() + private profitLossSheetTable: ProfitLossSheetTableInjectable; + + /** + * Retrieves the profit/loss sheet in XLSX format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IProfitLossSheetQuery) { + const table = await this.profitLossSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the profit/loss sheet in CSV format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IProfitLossSheetQuery + ): Promise { + const table = await this.profitLossSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts index 14d17fc5a..20cf9a170 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts @@ -16,39 +16,10 @@ import { ProfitLossSheetRepository } from './ProfitLossSheetRepository'; @Service() export default class ProfitLossSheetService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; - - /** - * Retrieve the trial balance sheet meta. - * @param {number} tenantId - Tenant id. - * @returns {ITrialBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IProfitLossSheetMeta { - const settings = this.tenancy.settings(tenantId); - - const isCostComputeRunning = - this.inventoryService.isItemsCostComputeRunning(tenantId); - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - isCostComputeRunning: parseBoolean(isCostComputeRunning, false), - organizationName, - baseCurrency, - }; - } + private inventoryService: InventoryService; /** * Retrieve profit/loss sheet statement. @@ -56,7 +27,7 @@ export default class ProfitLossSheetService { * @param {IProfitLossSheetQuery} query * @return { } */ - profitLossSheet = async ( + public profitLossSheet = async ( tenantId: number, query: IProfitLossSheetQuery ): Promise<{ @@ -70,13 +41,6 @@ export default class ProfitLossSheetService { // Merges the given query with default filter query. const filter = mergeQueryWithDefaults(query); - // Get the given accounts or throw not found service error. - // if (filter.accountsIds.length > 0) { - // await this.accountsService.getAccountsOrThrowError( - // tenantId, - // filter.accountsIds - // ); - // } const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -101,4 +65,30 @@ export default class ProfitLossSheetService { meta: this.reportMetadata(tenantId), }; }; + + /** + * Retrieve the trial balance sheet meta. + * @param {number} tenantId - Tenant id. + * @returns {ITrialBalanceSheetMeta} + */ + private reportMetadata(tenantId: number): IProfitLossSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = + this.inventoryService.isItemsCostComputeRunning(tenantId); + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency, + }; + } } diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts new file mode 100644 index 000000000..326e7aaef --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts @@ -0,0 +1,42 @@ +import { Inject, Service } from 'typedi'; +import ProfitLossSheetService from './ProfitLossSheetService'; +import { ProfitLossSheetTable } from './ProfitLossSheetTable'; +import { IProfitLossSheetQuery, IProfitLossSheetTable } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; + +@Service() +export class ProfitLossSheetTableInjectable { + @Inject() + private profitLossSheet: ProfitLossSheetService; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the profit/loss sheet in table format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: IProfitLossSheetQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data, query, meta } = await this.profitLossSheet.profitLossSheet( + tenantId, + filter + ); + const table = new ProfitLossSheetTable(data, query, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query, + meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts index 7570ef572..6f81e1489 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts @@ -87,10 +87,6 @@ export default class SalesByItemsReportService { ...this.defaultQuery, ...query, }; - this.logger.info('[sales_by_items] trying to calculate the report.', { - filter, - tenantId, - }); // Inventory items for sales report. const inventoryItems = await Item.query().onBuild((q) => { q.where('type', 'inventory'); diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts new file mode 100644 index 000000000..f0e5a5248 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts @@ -0,0 +1,63 @@ +import { Inject, Service } from 'typedi'; +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; +import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; +import { SalesTaxLiabilitySummaryExportInjectable } from './SalesTaxLiabilitySummaryExportInjectable'; +import { SalesTaxLiabilitySummaryService } from './SalesTaxLiabilitySummaryService'; + +@Service() +export class SalesTaxLiabilitySummaryApplication { + @Inject() + private salesTaxLiabilitySheet: SalesTaxLiabilitySummaryService; + + @Inject() + private salesTaxLiabilityExport: SalesTaxLiabilitySummaryExportInjectable; + + @Inject() + private salesTaxLiabilityTable: SalesTaxLiabilitySummaryTableInjectable; + + /** + * Retrieves the sales tax liability summary in json format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: SalesTaxLiabilitySummaryQuery) { + return this.salesTaxLiabilitySheet.salesTaxLiability(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in table format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @return {Promise} + */ + public table(tenantId: number, query: SalesTaxLiabilitySummaryQuery) { + return this.salesTaxLiabilityTable.table(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in XLSX format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + return this.salesTaxLiabilityExport.xlsx(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in CSV format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + return this.salesTaxLiabilityExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts new file mode 100644 index 000000000..932743679 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts @@ -0,0 +1,46 @@ +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { Inject, Service } from 'typedi'; +import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; + +@Service() +export class SalesTaxLiabilitySummaryExportInjectable { + @Inject() + private salesTaxLiabilityTable: SalesTaxLiabilitySummaryTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const table = await this.salesTaxLiabilityTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const table = await this.salesTaxLiabilityTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts index 09fa9283b..a1ec7a771 100644 --- a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts @@ -5,7 +5,6 @@ import { SalesTaxLiabilitySummaryQuery, } from '@/interfaces/SalesTaxLiabilitySummary'; import { SalesTaxLiabilitySummary } from './SalesTaxLiabilitySummary'; -import { SalesTaxLiabilitySummaryTable } from './SalesTaxLiabilitySummaryTable'; import HasTenancyService from '@/services/Tenancy/TenancyService'; @Service() @@ -47,32 +46,6 @@ export class SalesTaxLiabilitySummaryService { }; } - /** - * Retrieve sales tax liability summary table. - * @param {number} tenantId - * @param {SalesTaxLiabilitySummaryQuery} query - * @returns - */ - public async salesTaxLiabilitySummaryTable( - tenantId: number, - query: SalesTaxLiabilitySummaryQuery - ) { - const report = await this.salesTaxLiability(tenantId, query); - - // Creates the sales tax liability summary table. - const table = new SalesTaxLiabilitySummaryTable(report.data, query); - - return { - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - data: report.data, - query: report.query, - meta: report.meta, - }; - } - /** * Retrieve the report meta. * @param {number} tenantId - diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts new file mode 100644 index 000000000..907cab2ad --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts @@ -0,0 +1,40 @@ +import { Inject, Service } from 'typedi'; +import { + ISalesTaxLiabilitySummaryTable, + SalesTaxLiabilitySummaryQuery, +} from '@/interfaces/SalesTaxLiabilitySummary'; +import { SalesTaxLiabilitySummaryTable } from './SalesTaxLiabilitySummaryTable'; +import { SalesTaxLiabilitySummaryService } from './SalesTaxLiabilitySummaryService'; + +@Service() +export class SalesTaxLiabilitySummaryTableInjectable { + @Inject() + private salesTaxLiability: SalesTaxLiabilitySummaryService; + + /** + * Retrieve sales tax liability summary table. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const report = await this.salesTaxLiability.salesTaxLiability( + tenantId, + query + ); + // Creates the sales tax liability summary table. + const table = new SalesTaxLiabilitySummaryTable(report.data, query); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: report.query, + meta: report.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts index 3ab624830..e35692bd5 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts @@ -139,11 +139,4 @@ export default class TransactionsByCustomers extends TransactionsByContact { public reportData(): ITransactionsByCustomersData { return this.customersMapper(this.customers); } - - /** - * Retrieve the report columns. - */ - public reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts new file mode 100644 index 000000000..b729c219a --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts @@ -0,0 +1,72 @@ +import { Inject, Service } from 'typedi'; +import { + ITransactionsByCustomersFilter, + ITransactionsByCustomersStatement, +} from '@/interfaces'; +import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; +import { TransactionsByCustomersExportInjectable } from './TransactionsByCustomersExportInjectable'; +import { TransactionsByCustomersSheet } from './TransactionsByCustomersService'; + +@Service() +export class TransactionsByCustomerApplication { + @Inject() + private transactionsByCustomersTable: TransactionsByCustomersTableInjectable; + + @Inject() + private transactionsByCustomersExport: TransactionsByCustomersExportInjectable; + + @Inject() + private transactionsByCustomersSheet: TransactionsByCustomersSheet; + + /** + * Retrieves the transactions by customers sheet in json format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersSheet.transactionsByCustomers( + tenantId, + query + ); + } + + /** + * Retrieves the transactions by vendors sheet in table format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public table(tenantId: number, query: ITransactionsByCustomersFilter) { + return this.transactionsByCustomersTable.table(tenantId, query); + } + + /** + * Retrieves the transactions by vendors sheet in CSV format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersExport.csv(tenantId, query); + } + + /** + * Retrieves the transactions by vendors sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts new file mode 100644 index 000000000..d5dbffcff --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByCustomersFilter } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; + +@Service() +export class TransactionsByCustomersExportInjectable { + @Inject() + private transactionsByCustomerTable: TransactionsByCustomersTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const table = await this.transactionsByCustomerTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const table = await this.transactionsByCustomerTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts index fd66d8f1e..09579e2b2 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts @@ -1,16 +1,16 @@ +import { Inject } from 'typedi'; import { isEmpty, map } from 'lodash'; import { IAccount, IAccountTransaction } from '@/interfaces'; import { ACCOUNT_TYPE } from '@/data/AccountTypes'; import HasTenancyService from '@/services/Tenancy/TenancyService'; -import { Inject } from 'typedi'; export default class TransactionsByCustomersRepository { @Inject() - tenancy: HasTenancyService; + private tenancy: HasTenancyService; /** * Retrieve the report customers. - * @param {number} tenantId + * @param {number} tenantId * @returns {Promise} */ public async getCustomers(tenantId: number, customersIds?: number[]) { diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts index a6f56d9fe..3fbf8cf06 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts @@ -13,23 +13,20 @@ import Ledger from '@/services/Accounting/Ledger'; import TransactionsByCustomersRepository from './TransactionsByCustomersRepository'; import { Tenant } from '@/system/models'; -export default class TransactionsByCustomersService +export class TransactionsByCustomersSheet implements ITransactionsByCustomersService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - reportRepository: TransactionsByCustomersRepository; + private reportRepository: TransactionsByCustomersRepository; /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} */ - get defaultQuery(): ITransactionsByCustomersFilter { + private get defaultQuery(): ITransactionsByCustomersFilter { return { fromDate: moment().startOf('month').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -165,7 +162,6 @@ export default class TransactionsByCustomersService return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts similarity index 81% rename from packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts rename to packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts index 5c4e1ceb3..7016cf853 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts @@ -1,6 +1,6 @@ import * as R from 'ramda'; -import { tableRowMapper, tableMapper } from 'utils'; -import { ITransactionsByCustomersCustomer, ITableRow } from '@/interfaces'; +import { tableRowMapper } from 'utils'; +import { ITransactionsByCustomersCustomer, ITableRow, ITableColumn } from '@/interfaces'; import TransactionsByContactsTableRows from '../TransactionsByContact/TransactionsByContactTableRows'; enum ROW_TYPE { @@ -10,17 +10,14 @@ enum ROW_TYPE { CUSTOMER = 'CUSTOMER', } -export default class TransactionsByCustomersTableRows extends TransactionsByContactsTableRows { +export class TransactionsByCustomersTable extends TransactionsByContactsTableRows { private customersTransactions: ITransactionsByCustomersCustomer[]; /** * Constructor method. * @param {ITransactionsByCustomersCustomer[]} customersTransactions - Customers transactions. */ - constructor( - customersTransactions: ITransactionsByCustomersCustomer[], - i18n - ) { + constructor(customersTransactions: ITransactionsByCustomersCustomer[], i18n) { super(); this.customersTransactions = customersTransactions; this.i18n = i18n; @@ -75,4 +72,12 @@ export default class TransactionsByCustomersTableRows extends TransactionsByCont this.customersTransactions ); }; + + /** + * Retrieve the table columns of transactions by customers report. + * @returns {ITableColumn[]} + */ + public tableColumns = (): ITableColumn[] => { + return []; + } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts new file mode 100644 index 000000000..fb1c61311 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByCustomersFilter, ITransactionsByCustomersTable } from '@/interfaces'; +import { TransactionsByCustomersSheet } from './TransactionsByCustomersService'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { TransactionsByCustomersTable } from './TransactionsByCustomersTable'; + +@Service() +export class TransactionsByCustomersTableInjectable { + @Inject() + private transactionsByCustomerService: TransactionsByCustomersSheet; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the transactions by customers sheet in table format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: ITransactionsByCustomersFilter + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const customersTransactions = + await this.transactionsByCustomerService.transactionsByCustomers( + tenantId, + filter + ); + const table = new TransactionsByCustomersTable( + customersTransactions.data, + i18n + ); + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: customersTransactions.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts index 5bc9276c0..500e548f7 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts @@ -137,11 +137,4 @@ export default class TransactionsByVendors extends TransactionsByContact { public reportData(): ITransactionsByVendorsData { return this.vendorsMapper(this.contacts); } - - /** - * Retrieve the report columns. - */ - public reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts new file mode 100644 index 000000000..d8d424a30 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts @@ -0,0 +1,75 @@ +import { Inject, Service } from 'typedi'; +import { + ITransactionsByVendorTable, + ITransactionsByVendorsFilter, + ITransactionsByVendorsStatement, +} from '@/interfaces'; +import { TransactionsByVendorExportInjectable } from './TransactionsByVendorExportInjectable'; +import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; +import { TransactionsByVendorsInjectable } from './TransactionsByVendorInjectable'; + +@Service() +export class TransactionsByVendorApplication { + @Inject() + private transactionsByVendorTable: TransactionsByVendorTableInjectable; + + @Inject() + private transactionsByVendorExport: TransactionsByVendorExportInjectable; + + @Inject() + private transactionsByVendorSheet: TransactionsByVendorsInjectable; + + /** + * Retrieves the transactions by vendor in sheet format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorSheet.transactionsByVendors( + tenantId, + query + ); + } + + /** + * Retrieves the transactions by vendor in table format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public table( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorTable.table(tenantId, query); + } + + /** + * Retrieves the transactions by vendor in CSV format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorExport.csv(tenantId, query); + } + + /** + * Retrieves the transactions by vendor in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + */ + public xlsx( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts new file mode 100644 index 000000000..1d547e752 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByVendorsFilter } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; + +@Service() +export class TransactionsByVendorExportInjectable { + @Inject() + private transactionsByVendorTable: TransactionsByVendorTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const table = await this.transactionsByVendorTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const table = await this.transactionsByVendorTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts similarity index 94% rename from packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts rename to packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts index c112a059a..a24041929 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts @@ -1,7 +1,6 @@ import { Inject } from 'typedi'; import moment from 'moment'; import * as R from 'ramda'; -import { map } from 'lodash'; import TenancyService from '@/services/Tenancy/TenancyService'; import { ITransactionsByVendorsService, @@ -14,17 +13,14 @@ import Ledger from '@/services/Accounting/Ledger'; import TransactionsByVendorRepository from './TransactionsByVendorRepository'; import { Tenant } from '@/system/models'; -export default class TransactionsByVendorsService +export class TransactionsByVendorsInjectable implements ITransactionsByVendorsService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - reportRepository: TransactionsByVendorRepository; + private reportRepository: TransactionsByVendorRepository; /** * Defaults balance sheet filter query. @@ -136,7 +132,7 @@ export default class TransactionsByVendorsService const { accountRepository } = this.tenancy.repositories(tenantId); const i18n = this.tenancy.i18n(tenantId); - + const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -171,7 +167,6 @@ export default class TransactionsByVendorsService ); return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts similarity index 76% rename from packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts rename to packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts index e37eeb8fe..14ad3c1b4 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts @@ -1,6 +1,10 @@ import * as R from 'ramda'; import { tableRowMapper } from 'utils'; -import { ITransactionsByVendorsVendor, ITableRow } from '@/interfaces'; +import { + ITransactionsByVendorsVendor, + ITableRow, + ITableColumn, +} from '@/interfaces'; import TransactionsByContactsTableRows from '../TransactionsByContact/TransactionsByContactTableRows'; enum ROW_TYPE { @@ -10,16 +14,15 @@ enum ROW_TYPE { VENDOR = 'VENDOR', } -export default class TransactionsByVendorsTableRows extends TransactionsByContactsTableRows { - vendorsTransactions: ITransactionsByVendorsVendor[]; +export class TransactionsByVendorsTable extends TransactionsByContactsTableRows { + private vendorsTransactions: ITransactionsByVendorsVendor[]; /** * Constructor method. + * @param {ITransactionsByVendorsVendor[]} vendorsTransactions - + * @param {any} i18n */ - constructor( - vendorsTransactions: ITransactionsByVendorsVendor[], - i18n - ) { + constructor(vendorsTransactions: ITransactionsByVendorsVendor[], i18n) { super(); this.vendorsTransactions = vendorsTransactions; @@ -73,4 +76,12 @@ export default class TransactionsByVendorsTableRows extends TransactionsByContac public tableRows = (): ITableRow[] => { return R.map(this.vendorRowsMapper)(this.vendorsTransactions); }; + + /** + * Retrieve the table columns of transactions by vendors report. + * @returns {ITableColumn[]} + */ + public tableColumns = (): ITableColumn[] => { + return []; + }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts new file mode 100644 index 000000000..5b42b88e7 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { TransactionsByVendorsTable } from './TransactionsByVendorTable'; +import { + ITransactionsByVendorTable, + ITransactionsByVendorsFilter, +} from '@/interfaces'; +import { TransactionsByVendorsInjectable } from './TransactionsByVendorInjectable'; + +@Service() +export class TransactionsByVendorTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private transactionsByVendor: TransactionsByVendorsInjectable; + + /** + * Retrieves the transactions by vendor in table format. + * @param {number} tenantId + * @param {ITransactionsByReferenceQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const sheet = await this.transactionsByVendor.transactionsByVendors( + tenantId, + query + ); + const table = new TransactionsByVendorsTable(sheet.data, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts new file mode 100644 index 000000000..a515f1beb --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts @@ -0,0 +1,43 @@ +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ITrialBalanceSheetQuery } from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; + +@Service() +export class TrialBalanceExportInjectable { + @Inject() + private trialBalanceSheetTable: TrialBalanceSheetTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ITrialBalanceSheetQuery) { + const table = await this.trialBalanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const table = await this.trialBalanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts new file mode 100644 index 000000000..a771c8f15 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; +import { TrialBalanceExportInjectable } from './TrialBalanceExportInjectable'; +import { ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces'; +import TrialBalanceSheetService from './TrialBalanceSheetInjectable'; + +@Service() +export class TrialBalanceSheetApplication { + @Inject() + private sheetService: TrialBalanceSheetService; + + @Inject() + private tablable: TrialBalanceSheetTableInjectable; + + @Inject() + private exportable: TrialBalanceExportInjectable; + + /** + * Retrieves the trial balance sheet. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + return this.sheetService.trialBalanceSheet(tenantId, query); + } + + /** + * Retrieves the trial balance sheet in table format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.tablable.table(tenantId, query); + } + + /** + * Retrieve the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.exportable.csv(tenantId, query); + } + + /** + * Retrieve the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.exportable.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts similarity index 78% rename from packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts rename to packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts index 150f160b0..bc880ec99 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts @@ -1,7 +1,6 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import TenancyService from '@/services/Tenancy/TenancyService'; -import Journal from '@/services/Accounting/JournalPoster'; import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, @@ -13,7 +12,6 @@ import InventoryService from '@/services/Inventory/Inventory'; import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository'; -import { TrialBalanceSheetTable } from './TrialBalanceSheetTable'; @Service() export default class TrialBalanceSheetService extends FinancialSheet { @@ -30,7 +28,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { * Defaults trial balance sheet filter query. * @return {IBalanceSheetQuery} */ - get defaultQuery(): ITrialBalanceSheetQuery { + private get defaultQuery(): ITrialBalanceSheetQuery { return { fromDate: moment().startOf('year').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -54,7 +52,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { * @param {number} tenantId - Tenant id. * @returns {ITrialBalanceSheetMeta} */ - reportMetadata(tenantId: number): ITrialBalanceSheetMeta { + private reportMetadata(tenantId: number): ITrialBalanceSheetMeta { const settings = this.tenancy.settings(tenantId); const isCostComputeRunning = @@ -89,7 +87,6 @@ export default class TrialBalanceSheetService extends FinancialSheet { ...this.defaultQuery, ...query, }; - const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -120,27 +117,4 @@ export default class TrialBalanceSheetService extends FinancialSheet { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves the trial balance sheet table. - * @param {number} tenantId - * @param {ITrialBalanceSheetQuery} query - * @returns {Promise} - */ - public async trialBalanceSheetTable( - tenantId: number, - query: ITrialBalanceSheetQuery - ) { - const trialBalance = await this.trialBalanceSheet(tenantId, query); - const table = new TrialBalanceSheetTable(trialBalance.data, query, {}); - - return { - table: { - columns: table.tableColumns(), - rows: table.tableRows(), - }, - meta: trialBalance.meta, - query: trialBalance.query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts new file mode 100644 index 000000000..e62a1dde2 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts @@ -0,0 +1,33 @@ +import { Inject, Service } from 'typedi'; +import { ITrialBalanceSheetQuery, ITrialBalanceSheetTable } from '@/interfaces'; +import { TrialBalanceSheetTable } from './TrialBalanceSheetTable'; +import TrialBalanceSheetService from './TrialBalanceSheetInjectable'; + +@Service() +export class TrialBalanceSheetTableInjectable { + @Inject() + private sheet: TrialBalanceSheetService; + + /** + * Retrieves the trial balance sheet table. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const trialBalance = await this.sheet.trialBalanceSheet(tenantId, query); + const table = new TrialBalanceSheetTable(trialBalance.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: trialBalance.meta, + query: trialBalance.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts index 1d84d593f..2e5e09aa4 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts @@ -101,8 +101,4 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport { return { vendors, total }; } - - reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts new file mode 100644 index 000000000..5fe4bc74d --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts @@ -0,0 +1,62 @@ +import { Inject, Service } from 'typedi'; +import { IVendorBalanceSummaryQuery } from '@/interfaces'; +import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; +import { VendorBalanceSummaryExportInjectable } from './VendorBalanceSummaryExportInjectable'; +import { VendorBalanceSummaryService } from './VendorBalanceSummaryService'; + +@Service() +export class VendorBalanceSummaryApplication { + @Inject() + private vendorBalanceSummaryTable: VendorBalanceSummaryTableInjectable; + + @Inject() + private vendorBalanceSummarySheet: VendorBalanceSummaryService; + + @Inject() + private vendorBalanceSummaryExport: VendorBalanceSummaryExportInjectable; + + /** + * Retrieves the vendor balance summary sheet in sheet format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + */ + public sheet(tenantId: number, query: IVendorBalanceSummaryQuery) { + return this.vendorBalanceSummarySheet.vendorBalanceSummary(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in table format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {} + */ + public table(tenantId: number, query: IVendorBalanceSummaryQuery) { + return this.vendorBalanceSummaryTable.table(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in xlsx format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + return this.vendorBalanceSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in csv format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + return this.vendorBalanceSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts new file mode 100644 index 000000000..ba278f88d --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IVendorBalanceSummaryQuery } from '@/interfaces'; +import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; + +@Service() +export class VendorBalanceSummaryExportInjectable { + @Inject() + private customerBalanceSummaryTable: VendorBalanceSummaryTableInjectable; + + /** + * Retrieves the vendor balance summary sheet in XLSX format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IVendorBalanceSummaryQuery) { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the vendor balance summary sheet in CSV format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts index a8d67089d..721291b7d 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts @@ -7,7 +7,7 @@ import { ACCOUNT_TYPE } from '@/data/AccountTypes'; @Service() export default class VendorBalanceSummaryRepository { @Inject() - tenancy: HasTenancyService; + private tenancy: HasTenancyService; /** * Retrieve the report vendors. diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts index 82dc0475d..b1a361b87 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts @@ -1,10 +1,8 @@ import { Inject } from 'typedi'; import moment from 'moment'; -import { map } from 'lodash'; import * as R from 'ramda'; import TenancyService from '@/services/Tenancy/TenancyService'; import { - IVendor, IVendorBalanceSummaryService, IVendorBalanceSummaryQuery, IVendorBalanceSummaryStatement, @@ -15,15 +13,12 @@ import Ledger from '@/services/Accounting/Ledger'; import VendorBalanceSummaryRepository from './VendorBalanceSummaryRepository'; import { Tenant } from '@/system/models'; -export default class VendorBalanceSummaryService +export class VendorBalanceSummaryService implements IVendorBalanceSummaryService { @Inject() tenancy: TenancyService; - @Inject('logger') - logger: any; - @Inject() reportRepo: VendorBalanceSummaryRepository; @@ -31,7 +26,7 @@ export default class VendorBalanceSummaryService * Defaults balance sheet filter query. * @return {IVendorBalanceSummaryQuery} */ - get defaultQuery(): IVendorBalanceSummaryQuery { + private get defaultQuery(): IVendorBalanceSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), numberFormat: { @@ -72,7 +67,7 @@ export default class VendorBalanceSummaryService * @param {IVendorBalanceSummaryQuery} query - * @return {Promise} */ - async vendorBalanceSummary( + public async vendorBalanceSummary( tenantId: number, query: IVendorBalanceSummaryQuery ): Promise { @@ -81,13 +76,7 @@ export default class VendorBalanceSummaryService .withGraphFetched('metadata'); const filter = { ...this.defaultQuery, ...query }; - this.logger.info( - '[customer_balance_summary] trying to calculate the report.', - { - filter, - tenantId, - } - ); + // Retrieve the vendors transactions. const vendorsEntries = await this.getReportVendorsEntries( tenantId, @@ -111,7 +100,6 @@ export default class VendorBalanceSummaryService return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts new file mode 100644 index 000000000..aec97e6f1 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts @@ -0,0 +1,44 @@ +import { + IVendorBalanceSummaryQuery, + IVendorBalanceSummaryTable, +} from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { Inject, Service } from 'typedi'; +import { VendorBalanceSummaryTable } from './VendorBalanceSummaryTableRows'; +import { VendorBalanceSummaryService } from './VendorBalanceSummaryService'; + +@Service() +export class VendorBalanceSummaryTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private vendorBalanceSummarySheet: VendorBalanceSummaryService; + + /** + * Retrieves the vendor balance summary sheet in table format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data } = await this.vendorBalanceSummarySheet.vendorBalanceSummary( + tenantId, + query + ); + const table = new VendorBalanceSummaryTable(data, query, i18n); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts index d65ced56e..2095ea087 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts @@ -15,7 +15,7 @@ enum TABLE_ROWS_TYPES { TOTAL = 'TOTAL', } -export default class VendorBalanceSummaryTable { +export class VendorBalanceSummaryTable { i18n: any; report: IVendorBalanceSummaryData; query: IVendorBalanceSummaryQuery; diff --git a/packages/server/src/utils/deepdash.ts b/packages/server/src/utils/deepdash.ts index 6a97209e0..0ce65216a 100644 --- a/packages/server/src/utils/deepdash.ts +++ b/packages/server/src/utils/deepdash.ts @@ -78,6 +78,27 @@ const filterNodesDeep = (predicate, nodes) => { ); }; +const flatNestedTree = (obj, mapper, options) => { + return reduceDeep( + obj, + (accumulator, value, key, parentValue, context) => { + const computedValue = _.omit(value, ['children']); + const mappedValue = mapper + ? mapper(computedValue, key, context) + : computedValue; + + accumulator.push(mappedValue); + return accumulator; + }, + [], + { + childrenPath: 'children', + pathFormat: 'array', + ...options, + } + ); +}; + export { iteratee, condense, @@ -103,4 +124,5 @@ export { someDeep, mapValuesDeepReverse, filterNodesDeep, + flatNestedTree, }; diff --git a/packages/server/src/utils/table.ts b/packages/server/src/utils/table.ts index a6d39be94..74f5c3170 100644 --- a/packages/server/src/utils/table.ts +++ b/packages/server/src/utils/table.ts @@ -22,7 +22,9 @@ export function tableRowMapper( ): ITableRow { const cells = columns.map((column) => ({ key: column.key, - value: column.value ? column.value : getAccessor(object, column.accessor), + value: column.value + ? column.value + : getAccessor(object, column.accessor) || '', })); return { diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx index de806ab2f..f0473ab58 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx @@ -15,6 +15,7 @@ import { DashboardActionsBar, FormattedMessage as T, Icon } from '@/components'; import { useAPAgingSummaryContext } from './APAgingSummaryProvider'; import NumberFormatDropdown from '@/components/NumberFormatDropdown'; +import { APAgingSummaryExportMenu } from './components'; import withAPAgingSummary from './withAPAgingSummary'; import withAPAgingSummaryActions from './withAPAgingSummaryActions'; @@ -106,11 +107,18 @@ function APAgingSummaryActionsBar({ icon={} text={} /> -