mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74b6e41cd4 | ||
|
|
d239003047 |
@@ -159,15 +159,6 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"login": "nklmantey",
|
|
||||||
"name": "Mantey",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/u/90279429?v=4",
|
|
||||||
"profile": "https://nklmantey.com/",
|
|
||||||
"contributions": [
|
|
||||||
"bug"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
|||||||
@@ -92,11 +92,4 @@ S3_BUCKET=
|
|||||||
|
|
||||||
# PostHog
|
# PostHog
|
||||||
POSTHOG_API_KEY=
|
POSTHOG_API_KEY=
|
||||||
POSTHOG_HOST=
|
POSTHOG_HOST=
|
||||||
|
|
||||||
# Stripe Payment
|
|
||||||
STRIPE_PAYMENT_SECRET_KEY=
|
|
||||||
STRIPE_PAYMENT_PUBLISHABLE_KEY=
|
|
||||||
STRIPE_PAYMENT_CLIENT_ID=
|
|
||||||
STRIPE_PAYMENT_WEBHOOKS_SECRET=
|
|
||||||
STRIPE_PAYMENT_REDIRECT_URL=
|
|
||||||
195
CHANGELOG.md
195
CHANGELOG.md
@@ -2,191 +2,7 @@
|
|||||||
|
|
||||||
All notable changes to Bigcapital server-side will be in this file.
|
All notable changes to Bigcapital server-side will be in this file.
|
||||||
|
|
||||||
# [0.22.0]
|
## [0.19.4] - 18-08-2024
|
||||||
|
|
||||||
* feat: estimate, receipt, credit note mail preview by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/757
|
|
||||||
* feat: Add discount to transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/758
|
|
||||||
* fix: update financial forms to use new formatted amount utilities and… by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/760
|
|
||||||
* fix: total lines style by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/761
|
|
||||||
* fix: discount & adjustment sale transactions bugs by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/762
|
|
||||||
* fix: discount transactions GL entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/763
|
|
||||||
|
|
||||||
# [0.21.2]
|
|
||||||
|
|
||||||
* hotbug: upload attachments by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/755
|
|
||||||
|
|
||||||
# [0.21.1]
|
|
||||||
|
|
||||||
* fix: download invoice document on payment page by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/750
|
|
||||||
* fix: attach branding template attrs to payment page by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/751
|
|
||||||
* fix: make manual entries adjust decimal credit/debit amounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/754
|
|
||||||
* feat: allow quantity of entries accept decimal value by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/753
|
|
||||||
|
|
||||||
# [0.21.0]
|
|
||||||
|
|
||||||
* fix: Credit and debit totals not balancing when decimal values are used by @nklmantey in https://github.com/bigcapitalhq/bigcapital/pull/722
|
|
||||||
* docs: add nklmantey as a contributor for bug by @allcontributors in https://github.com/bigcapitalhq/bigcapital/pull/725
|
|
||||||
* feat: track more services events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/721
|
|
||||||
* feat: Invoice mail receipt preview by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/723
|
|
||||||
* fix: change the send mail button on invoice drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/730
|
|
||||||
* refactor: notification mail services by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/731
|
|
||||||
* fix: attach payment link in sending invoice mail receipt by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/732
|
|
||||||
* fix: send invoice drawer layout by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/733
|
|
||||||
* fix: hook up cc and bcc fields to mail sender by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/734
|
|
||||||
* fix: company logo does not show up in mail receipt preview by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/736
|
|
||||||
* fix: change default invoice mail message by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/737
|
|
||||||
* fix: typing invoice send mail fields by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/738
|
|
||||||
* fix: clean up ivnoice mail receipt preview component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/739
|
|
||||||
* feat: add shared package to pdf templates to render in the server and… by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/735
|
|
||||||
* feat: getting invoice preview on send mail view by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/740
|
|
||||||
* fix: style SSR invoice paper template by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/741
|
|
||||||
* fix: send invoice receipt addresses by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/742
|
|
||||||
* fix: due invoice server invoice by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/744
|
|
||||||
* fix: `BIG-265` forgot password text by @ibutiti in https://github.com/bigcapitalhq/bigcapital/pull/745
|
|
||||||
* Crims on sv translation by @Crims-on in https://github.com/bigcapitalhq/bigcapital/pull/671
|
|
||||||
* feat: Added Spanish language to the App 🇪🇸 by @angelosorno in https://github.com/bigcapitalhq/bigcapital/pull/530
|
|
||||||
* fix: mail services by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/746
|
|
||||||
* fix: company logo of the template by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/747
|
|
||||||
* fix: monorepo dependencies scope by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/748
|
|
||||||
|
|
||||||
# [0.20.6]
|
|
||||||
|
|
||||||
* fix: Import category column of item resource by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/710
|
|
||||||
* fix: Parse the uppercase values in importing by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/711
|
|
||||||
* chore: Move i18nApply localization to the account transformer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/713
|
|
||||||
* fix: Sync Plaid credit card account type by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/714
|
|
||||||
* fix: Sync account normal of cashflow GL entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/715
|
|
||||||
* feat: Add quantity column to pdf templates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/716
|
|
||||||
* feat: Pre-line invoice statements by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/717
|
|
||||||
* feat: Invoice number in downloaded pdf document by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/718
|
|
||||||
* feat: Track events of pdf documents views by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/719
|
|
||||||
* fix: Customer note does not appear in pdf document by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/720
|
|
||||||
|
|
||||||
# [0.20.5]
|
|
||||||
|
|
||||||
* fix: Disable tabs of the pdf customization if the first field not filed up by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/701
|
|
||||||
* fix: Invoice form layout by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/705
|
|
||||||
* refactor: Invoice, estimate, receipt, credit note and payment received date input fields by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/707
|
|
||||||
* feat: Add customize templates button to edit forms by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/708
|
|
||||||
* feat: Track account, invoice and item viewed events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/709
|
|
||||||
|
|
||||||
# [0.20.4]
|
|
||||||
|
|
||||||
* fix: Delete company logo from the PDF template by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/699
|
|
||||||
* fix: Set max width/height to company logo of pdf templates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/700
|
|
||||||
|
|
||||||
# [0.20.3]
|
|
||||||
|
|
||||||
* feat: Assign default PDF template automatically by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/687
|
|
||||||
* fix: pdf template addresses controlling by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/688
|
|
||||||
* fix: Remove empty lines from address formats by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/690
|
|
||||||
* fix: Pdf templates layout by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/691
|
|
||||||
* feat: Download invoice pdf of the payment link by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/689
|
|
||||||
* fix: Display country name by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/693
|
|
||||||
* feat: Add shared packages to Docker container by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/694
|
|
||||||
|
|
||||||
# [0.20.2]
|
|
||||||
|
|
||||||
* feat: Assign default PDF template automatically by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/687
|
|
||||||
* fix: pdf template addresses controlling by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/688
|
|
||||||
* fix: Remove empty lines from address formats by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/690
|
|
||||||
* fix: Pdf templates layout by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/691
|
|
||||||
* feat: Download invoice pdf of the payment link by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/689
|
|
||||||
* fix: Display country name by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/693
|
|
||||||
* feat: Add shared packages to Docker container by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/694
|
|
||||||
|
|
||||||
# [0.20.1]
|
|
||||||
|
|
||||||
* fix: Getting uploaded object uri by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/684
|
|
||||||
|
|
||||||
# [0.20.0]
|
|
||||||
|
|
||||||
* feat: Customize pdf templates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/667
|
|
||||||
* feat: Onboard accounts to Stripe Connect by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/668
|
|
||||||
* feat: Upload company logo to invoice templates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/670
|
|
||||||
* fix: Invoice pdf customize by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/672
|
|
||||||
* fix: Invoice customize bugs by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/673
|
|
||||||
* feat: Clean up payment links endpoints by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/674
|
|
||||||
* feat: Hook up company logo to server-side pdf templates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/675
|
|
||||||
* feat: Company branding preferences by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/677
|
|
||||||
* feat: Pdf templates customer/company addresses by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/678
|
|
||||||
* fix: Listen to Stripe session completed event by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/679
|
|
||||||
* feat: Track pdf templates Posthog events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/680
|
|
||||||
* fix: Branding customize content by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/681
|
|
||||||
* feat: Listen to Stripe integration events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/682
|
|
||||||
* feat: Hook up customer/company address to invoice preview of payment page by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/683
|
|
||||||
|
|
||||||
# [0.19.17]
|
|
||||||
|
|
||||||
* fix: Un-categorize bank transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/663
|
|
||||||
|
|
||||||
# [0.19.16]
|
|
||||||
|
|
||||||
* feat: Tracking more Posthog events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/653
|
|
||||||
* fix: Expense cannot accept credit card as payment account by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/654
|
|
||||||
* fix: Suspense the lazy loaded components in banking pages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/657
|
|
||||||
* feat: Add help dropdown menu by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/656
|
|
||||||
* feat: Bank pages layout breaking by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/658
|
|
||||||
* feat: Datatable UI improvements by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/655
|
|
||||||
* fix: Array cast of recognize function rule ids by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/660
|
|
||||||
* fix: Payment made filling the form full amount field by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/661
|
|
||||||
* feat: Tabular number of all money columns by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/659
|
|
||||||
* refactor: The expense G/L writer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/662
|
|
||||||
|
|
||||||
## [0.19.15] -
|
|
||||||
|
|
||||||
* fix: Bank transactions infinity scrolling by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/648
|
|
||||||
* feat: Integrate multiple branches and warehouses to resource importing by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/645
|
|
||||||
* fix: Integrate multiple branches with expense resource by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/649
|
|
||||||
* feat: Cover more tracking events. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/650
|
|
||||||
* feat: Track banking service events by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/651
|
|
||||||
|
|
||||||
## [0.19.14]
|
|
||||||
|
|
||||||
* fix: Import bugs by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/643
|
|
||||||
* fix: Set default index to transaction entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/644
|
|
||||||
* feat(server): Events tracking using Posthog by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/646
|
|
||||||
|
|
||||||
## [0.19.13]
|
|
||||||
|
|
||||||
* fix: Subscription middleware by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/624
|
|
||||||
* fix: Getting the sheet columns in import sheet by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/641
|
|
||||||
|
|
||||||
## [0.19.12]
|
|
||||||
|
|
||||||
* fix: Typo one-click demo page by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/640
|
|
||||||
|
|
||||||
## [0.19.11]
|
|
||||||
|
|
||||||
* fix: Avoid running the cost job in import preview by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/635
|
|
||||||
* fix: Debounce scheduling calculating items cost by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/634
|
|
||||||
* fix: Expand the resources export page size limitation by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/636
|
|
||||||
* feat: Optimize loading perf. by splitting big chunks and lazy loading them by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/632
|
|
||||||
* fix: Use standard ISO 8601 format for exported data by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/638
|
|
||||||
* fix: Add customer type to customers resource by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/639
|
|
||||||
|
|
||||||
## [0.19.10]
|
|
||||||
|
|
||||||
* fix: Add subscription plans offer text by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/629
|
|
||||||
|
|
||||||
## [0.19.9]
|
|
||||||
|
|
||||||
* fix: Make webapp package env variables dynamic by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/628
|
|
||||||
|
|
||||||
## [v0.19.8]
|
|
||||||
|
|
||||||
* fix: Cannot import items income and cost accounts by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/617
|
|
||||||
* fix: Some bank account details hidden by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/618
|
|
||||||
* feat(ee): One-click demo account by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/616
|
|
||||||
* feat: change banking service language by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/619
|
|
||||||
* feat(banking): Filter uncategorized bank transactions by date by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/590
|
|
||||||
* Fix: Syntax error caused error by @wolone in https://github.com/bigcapitalhq/bigcapital/pull/622
|
|
||||||
* fix: Listen to payment webhooks by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/623
|
|
||||||
* fix: Add prefix J-00001 to manual journals increments by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/625
|
|
||||||
* fix: Disable sms service until Twilo integration by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/626
|
|
||||||
* fix: Style tweaks in onboarding page by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/627
|
|
||||||
|
|
||||||
## [0.19.5] - 18-08-2024
|
|
||||||
|
|
||||||
* fix: Allow multi-lines to statements transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/594
|
* fix: Allow multi-lines to statements transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/594
|
||||||
* feat: Add amount comparators to amount bank rule field by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/595
|
* feat: Add amount comparators to amount bank rule field by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/595
|
||||||
@@ -207,15 +23,6 @@ All notable changes to Bigcapital server-side will be in this file.
|
|||||||
* fix: Delete bank account with uncategorized transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/614
|
* fix: Delete bank account with uncategorized transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/614
|
||||||
* feat: activate/inactivate account from drawer details by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/615
|
* feat: activate/inactivate account from drawer details by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/615
|
||||||
|
|
||||||
## [v0.19.4]
|
|
||||||
|
|
||||||
* feat: Import and export tax rates by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/591
|
|
||||||
* feat: Un-categorize bank transactions in bulk by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/587
|
|
||||||
* feat: Pending bank transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/589
|
|
||||||
* fix: Update `dev` Script in `package.json` to Use `cross-env` by @Champetaman in https://github.com/bigcapitalhq/bigcapital/pull/588
|
|
||||||
* fix: Should not load branches on reconcile matching form if the branches not enabled by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/592
|
|
||||||
* fix: Rounding the total amount the pending and matched transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/593
|
|
||||||
|
|
||||||
## [v0.18.0] - 10-08-2024
|
## [v0.18.0] - 10-08-2024
|
||||||
|
|
||||||
* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
* feat: Bank rules for automated categorization by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/511
|
||||||
|
|||||||
@@ -12,9 +12,6 @@
|
|||||||
<a href="https://github.com/bigcapitalhq/bigcapital/commits/develop">
|
<a href="https://github.com/bigcapitalhq/bigcapital/commits/develop">
|
||||||
<img src="https://img.shields.io/github/commit-activity/m/bigcapitalhq/bigcapital/develop" />
|
<img src="https://img.shields.io/github/commit-activity/m/bigcapitalhq/bigcapital/develop" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://hub.docker.com/u/bigcapitalhq">
|
|
||||||
<img src="https://img.shields.io/docker/pulls/bigcapitalhq/webapp" />
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.com/invite/c8nPBJafeb">
|
<a href="https://discord.com/invite/c8nPBJafeb">
|
||||||
<img src="https://img.shields.io/discord/1066514716752625725?label=Discord" alt="" />
|
<img src="https://img.shields.io/discord/1066514716752625725?label=Discord" alt="" />
|
||||||
</a>
|
</a>
|
||||||
@@ -133,7 +130,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oleynikd"><img src="https://avatars.githubusercontent.com/u/3976868?v=4?s=100" width="100px;" alt="Denis"/><br /><sub><b>Denis</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aoleynikd" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oleynikd"><img src="https://avatars.githubusercontent.com/u/3976868?v=4?s=100" width="100px;" alt="Denis"/><br /><sub><b>Denis</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aoleynikd" title="Bug reports">🐛</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.camilooviedo.com/"><img src="https://avatars.githubusercontent.com/u/64604272?v=4?s=100" width="100px;" alt="Camilo Oviedo"/><br /><sub><b>Camilo Oviedo</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Champetaman" title="Code">💻</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://www.camilooviedo.com/"><img src="https://avatars.githubusercontent.com/u/64604272?v=4?s=100" width="100px;" alt="Camilo Oviedo"/><br /><sub><b>Camilo Oviedo</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Champetaman" title="Code">💻</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nklmantey.com/"><img src="https://avatars.githubusercontent.com/u/90279429?v=4?s=100" width="100px;" alt="Mantey"/><br /><sub><b>Mantey</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Anklmantey" title="Bug reports">🐛</a></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
"version": "independent",
|
"version": "independent",
|
||||||
"npmClient": "pnpm",
|
"npmClient": "pnpm",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*",
|
"packages/*"
|
||||||
"shared/*"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -4,11 +4,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "lerna run dev",
|
"dev": "lerna run dev",
|
||||||
"build": "lerna run build",
|
"build": "lerna run build",
|
||||||
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\"",
|
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
|
||||||
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\"",
|
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\"",
|
||||||
"dev:server": "lerna run dev --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\" --scope \"@bigcapital/email-components\"",
|
"dev:server": "lerna run dev --scope \"@bigcapital/server\"",
|
||||||
"build:server": "lerna run build --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\" --scope \"@bigcapital/email-components\"",
|
"build:server": "lerna run build --scope \"@bigcapital/server\"",
|
||||||
"serve:server": "lerna run serve --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
|
"serve:server": "lerna run serve --scope \"@bigcapital/server\"",
|
||||||
"test:e2e": "playwright test",
|
"test:e2e": "playwright test",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
@@ -29,8 +29,5 @@
|
|||||||
"hooks": {
|
"hooks": {
|
||||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tsup": "^8.3.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
packages/server/.gitignore
vendored
4
packages/server/.gitignore
vendored
@@ -4,5 +4,5 @@ stdout.log
|
|||||||
/dist
|
/dist
|
||||||
/build
|
/build
|
||||||
/public/imports
|
/public/imports
|
||||||
dist
|
|
||||||
newrelic_agent.log
|
dist
|
||||||
@@ -90,7 +90,11 @@ RUN chown node:node /
|
|||||||
RUN npm install -g pnpm
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
# Copy application dependency manifests to the container image.
|
# Copy application dependency manifests to the container image.
|
||||||
COPY --chown=node:node ./ ./
|
COPY ./package*.json ./
|
||||||
|
COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
|
||||||
|
COPY ./lerna.json ./lerna.json
|
||||||
|
COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
|
||||||
|
COPY ./packages/server/package*.json ./packages/server/
|
||||||
|
|
||||||
# Install application dependencies
|
# Install application dependencies
|
||||||
RUN apk update
|
RUN apk update
|
||||||
@@ -105,6 +109,6 @@ RUN pnpm install
|
|||||||
COPY --chown=node:node ./packages/server ./packages/server
|
COPY --chown=node:node ./packages/server ./packages/server
|
||||||
|
|
||||||
# # Creates a "dist" folder with the production build
|
# # Creates a "dist" folder with the production build
|
||||||
RUN pnpm run build:server --skip-nx-cache
|
RUN npm run build:server --skip-nx-cache
|
||||||
|
|
||||||
CMD [ "node", "./packages/server/build/index.js" ]
|
CMD [ "node", "./packages/server/build/index.js" ]
|
||||||
@@ -20,9 +20,6 @@
|
|||||||
"bigcapital": "./bin/bigcapital.js"
|
"bigcapital": "./bin/bigcapital.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bigcapital/utils": "*",
|
|
||||||
"@bigcapital/email-components": "*",
|
|
||||||
"@bigcapital/pdf-templates": "*",
|
|
||||||
"@aws-sdk/client-s3": "^3.576.0",
|
"@aws-sdk/client-s3": "^3.576.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.583.0",
|
"@aws-sdk/s3-request-presigner": "^3.583.0",
|
||||||
"@casl/ability": "^5.4.3",
|
"@casl/ability": "^5.4.3",
|
||||||
@@ -112,13 +109,12 @@
|
|||||||
"rtl-detect": "^1.0.4",
|
"rtl-detect": "^1.0.4",
|
||||||
"socket.io": "^4.7.4",
|
"socket.io": "^4.7.4",
|
||||||
"source-map-loader": "^4.0.1",
|
"source-map-loader": "^4.0.1",
|
||||||
"stripe": "^16.10.0",
|
"swagger-ui-express": "^5.0.1",
|
||||||
"tmp-promise": "^3.0.3",
|
"tmp-promise": "^3.0.3",
|
||||||
"ts-transformer-keys": "^0.4.2",
|
"ts-transformer-keys": "^0.4.2",
|
||||||
"tsyringe": "^4.3.0",
|
"tsyringe": "^4.3.0",
|
||||||
"typedi": "^0.8.0",
|
"typedi": "^0.8.0",
|
||||||
"uniqid": "^5.2.0",
|
"uniqid": "^5.2.0",
|
||||||
"uuid": "^10.0.0",
|
|
||||||
"winston": "^3.2.1",
|
"winston": "^3.2.1",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
"yup": "^0.28.1"
|
"yup": "^0.28.1"
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap');
|
|
||||||
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
text-align: -webkit-match-parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead,
|
|
||||||
tbody,
|
|
||||||
tfoot,
|
|
||||||
tr,
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
border-color: inherit;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body{
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #000;
|
|
||||||
background-color: #fff;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
body, h1, h2, h3, h4, h5, h6{
|
|
||||||
font-family: "Noto Sans", sans-serif;
|
|
||||||
font-optical-sizing: auto;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
@@ -1 +1,35 @@
|
|||||||
@import "./normalize.scss";
|
@import "./normalize.scss";
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: inherit; // 2
|
||||||
|
text-align: -webkit-match-parent; // 3
|
||||||
|
}
|
||||||
|
|
||||||
|
thead,
|
||||||
|
tbody,
|
||||||
|
tfoot,
|
||||||
|
tr,
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
border-color: inherit;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
background-color: #fff;
|
||||||
|
direction: ltr;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|||||||
379
packages/server/resources/scss/normalize.css
vendored
379
packages/server/resources/scss/normalize.css
vendored
@@ -1,379 +0,0 @@
|
|||||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
|
||||||
|
|
||||||
/* Document
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the line height in all browsers.
|
|
||||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
|
||||||
line-height: 1.15;
|
|
||||||
/* 1 */
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sections
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the margin in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the `main` element consistently in IE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
main {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the font size and margin on `h1` elements within `section` and
|
|
||||||
* `article` contexts in Chrome, Firefox, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
margin: 0.67em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grouping content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Add the correct box sizing in Firefox.
|
|
||||||
* 2. Show the overflow in Edge and IE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
/* 1 */
|
|
||||||
height: 0;
|
|
||||||
/* 1 */
|
|
||||||
overflow: visible;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pre {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
/* 1 */
|
|
||||||
font-size: 1em;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Text-level semantics
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the gray background on active links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Remove the bottom border in Chrome 57-
|
|
||||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abbr[title] {
|
|
||||||
border-bottom: none;
|
|
||||||
/* 1 */
|
|
||||||
text-decoration: underline;
|
|
||||||
/* 2 */
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
/* 1 */
|
|
||||||
font-size: 1em;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct font size in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
|
||||||
* all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Embedded content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the border on images inside links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forms
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Change the font styles in all browsers.
|
|
||||||
* 2. Remove the margin in Firefox and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
font-family: inherit;
|
|
||||||
/* 1 */
|
|
||||||
font-size: 100%;
|
|
||||||
/* 1 */
|
|
||||||
line-height: 1.15;
|
|
||||||
/* 1 */
|
|
||||||
margin: 0;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the overflow in IE.
|
|
||||||
* 1. Show the overflow in Edge.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
/* 1 */
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
|
||||||
* 1. Remove the inheritance of text transform in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
/* 1 */
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
[type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inner border and padding in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
border-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore the focus styles unset by the previous rule.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button:-moz-focusring,
|
|
||||||
[type="button"]:-moz-focusring,
|
|
||||||
[type="reset"]:-moz-focusring,
|
|
||||||
[type="submit"]:-moz-focusring {
|
|
||||||
outline: 1px dotted ButtonText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the padding in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
padding: 0.35em 0.75em 0.625em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the text wrapping in Edge and IE.
|
|
||||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
|
||||||
* 3. Remove the padding so developers are not caught out when they zero out
|
|
||||||
* `fieldset` elements in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
legend {
|
|
||||||
box-sizing: border-box;
|
|
||||||
/* 1 */
|
|
||||||
color: inherit;
|
|
||||||
/* 2 */
|
|
||||||
display: table;
|
|
||||||
/* 1 */
|
|
||||||
max-width: 100%;
|
|
||||||
/* 1 */
|
|
||||||
padding: 0;
|
|
||||||
/* 3 */
|
|
||||||
white-space: normal;
|
|
||||||
/* 1 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
|
||||||
*/
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the default vertical scrollbar in IE 10+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Add the correct box sizing in IE 10.
|
|
||||||
* 2. Remove the padding in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="checkbox"],
|
|
||||||
[type="radio"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
/* 1 */
|
|
||||||
padding: 0;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the odd appearance in Chrome and Safari.
|
|
||||||
* 2. Correct the outline style in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
-webkit-appearance: textfield;
|
|
||||||
/* 1 */
|
|
||||||
outline-offset: -2px;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the inner padding in Chrome and Safari on macOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
|
||||||
* 2. Change font properties to `inherit` in Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
/* 1 */
|
|
||||||
font: inherit;
|
|
||||||
/* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Interactive
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
details {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the correct display in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Misc
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct display in IE 10+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the correct display in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
html(lang=locale)
|
html(lang=locale)
|
||||||
head
|
head
|
||||||
title My Site - #{title}
|
title My Site - #{title}
|
||||||
style
|
|
||||||
include ../scss/normalize.css
|
|
||||||
include ../scss/base.css
|
|
||||||
block head
|
block head
|
||||||
body
|
body
|
||||||
div.paper-template
|
div.paper-template
|
||||||
|
|||||||
@@ -1,227 +1,81 @@
|
|||||||
extends ../PaperTemplateLayout.pug
|
extends ../PaperTemplateLayout.pug
|
||||||
|
|
||||||
block head
|
block head
|
||||||
- var prefix = 'bc'
|
style
|
||||||
style.
|
if (isRtl)
|
||||||
.#{prefix}-root {
|
include ../../css/modules/credit-rtl.css
|
||||||
color: #111;
|
else
|
||||||
padding: 24px 30px;
|
include ../../css/modules/credit.css
|
||||||
font-size: 12px;
|
|
||||||
position: relative;
|
|
||||||
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
|
|
||||||
}
|
|
||||||
.#{prefix}-header{
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: wrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
-webkit-box-align: start;
|
|
||||||
align-items: start;
|
|
||||||
-webkit-box-pack: start;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
.#{prefix}-header-details{
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: 20px;
|
|
||||||
flex: 1 1 0%;
|
|
||||||
}
|
|
||||||
.#{prefix}-big-title {
|
|
||||||
font-size: 30px;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.#{prefix}-logo-wrap img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 260px;
|
|
||||||
max-height: 100px;
|
|
||||||
}
|
|
||||||
.#{prefix}-terms-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
.#{prefix}-terms-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
.#{prefix}-terms-item__label {
|
|
||||||
min-width: 120px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.#{prefix}-terms-item__value {
|
|
||||||
/* Styles for the term value */
|
|
||||||
}
|
|
||||||
.#{prefix}-address-section{
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: wrap;
|
|
||||||
-webkit-box-align: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
-webkit-box-pack: start;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 10px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
.#{prefix}-address-section > * {
|
|
||||||
flex: 1 1;
|
|
||||||
}
|
|
||||||
.#{prefix}-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
text-align: left;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__header {
|
|
||||||
font-weight: 400;
|
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
padding: 2px 10px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__header:first-of-type{
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__header:last-of-type{
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__header--right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell {
|
|
||||||
border-bottom: 1px solid #F6F6F6;
|
|
||||||
padding: 12px 10px;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell:first-of-type{
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell:last-of-type {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell--right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell--item .item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
.#{prefix}-table__cell--item .item .item__description{
|
|
||||||
color: #5f6b7c;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-left: auto;
|
|
||||||
width: 300px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item {
|
|
||||||
display: flex;
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item--border-gray {
|
|
||||||
border-bottom: 1px solid #DADADA;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item--border-dark {
|
|
||||||
border-bottom: 1px solid #000;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item--font-weight-bold {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item-label {
|
|
||||||
min-width: 160px;
|
|
||||||
}
|
|
||||||
.#{prefix}-totals__item-amount {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.#{prefix}-statement {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.#{prefix}-statement__label {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
.#{prefix}-statement__value {
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div(class=`${prefix}-root`)
|
div.credit
|
||||||
|
div.credit__header
|
||||||
//- Header (includes big title, details and logo)
|
div.paper
|
||||||
div(class=`${prefix}-header`)
|
h1.title #{__('credit.paper.credit_note')}
|
||||||
//- Header details (includes big title and details)
|
if creditNote.creditNoteNumber
|
||||||
div(class=`${prefix}-header-details`)
|
span.creditNoteNumber #{creditNote.creditNoteNumber}
|
||||||
div(class=`${prefix}-big-title`) Credit Note
|
|
||||||
|
|
||||||
div(class=`${prefix}-terms-list`)
|
div.organization
|
||||||
if showCreditNoteNumber
|
h3.title #{organizationName}
|
||||||
div(class=`${prefix}-terms-item`)
|
if organizationEmail
|
||||||
div(class=`${prefix}-terms-item__label`) #{creditNoteNumberLabel}:
|
span.email #{organizationEmail}
|
||||||
div(class=`${prefix}-terms-item__value`) #{creditNoteNumebr}
|
|
||||||
|
|
||||||
if showCreditNoteDate
|
div.credit__full-amount
|
||||||
div(class=`${prefix}-terms-item`)
|
div.label #{__('credit.paper.amount')}
|
||||||
div(class=`${prefix}-terms-item__label`) #{creditNoteDateLabel}:
|
div.amount #{creditNote.formattedAmount}
|
||||||
div(class=`${prefix}-terms-item__value`) #{creditNoteDate}
|
|
||||||
|
|
||||||
if showCompanyLogo && companyLogoUri
|
div.credit__meta
|
||||||
div(class=`${prefix}-logo-wrap`)
|
div.credit__meta-item.credit__meta-item--amount
|
||||||
img(src=companyLogoUri alt=`Company Logo`)
|
span.label #{__('credit.paper.remaining')}
|
||||||
|
span.value #{creditNote.formattedCreditsRemaining}
|
||||||
|
|
||||||
div(class=`${prefix}-address-section`)
|
div.credit__meta-item.credit__meta-item--billed-to
|
||||||
if showCompanyAddress
|
span.label #{__("credit.paper.billed_to")}
|
||||||
div(class=`${prefix}-address-from`)
|
span.value #{creditNote.customer.displayName}
|
||||||
div !{companyAddress}
|
|
||||||
|
|
||||||
if showCustomerAddress
|
div.credit__meta-item.credit__meta-item--credit-date
|
||||||
div(class=`${prefix}-address-to`)
|
span.label #{__("credit.paper.credit_date")}
|
||||||
strong #{billedToLabel}
|
span.value #{creditNote.formattedCreditNoteDate}
|
||||||
div !{customerAddress}
|
|
||||||
|
|
||||||
table(class=`${prefix}-table`)
|
div.credit__table
|
||||||
thead
|
table
|
||||||
tr
|
thead
|
||||||
th(class=`${prefix}-table__header ${prefix}-table__header--item`) #{'Item'}
|
tr
|
||||||
th(class=`${prefix}-table__header ${prefix}-table__header--quantity ${prefix}-table__header--right`) #{'Quantity'}
|
th.item #{__("item_entry.paper.item_name")}
|
||||||
th(class=`${prefix}-table__header ${prefix}-table__header--rate ${prefix}-table__header--right`) #{'Rate'}
|
th.rate #{__("item_entry.paper.rate")}
|
||||||
th(class=`${prefix}-table__header ${prefix}-table__header--total ${prefix}-table__header--right`) #{'Total'}
|
th.quantity #{__("item_entry.paper.quantity")}
|
||||||
|
th.total #{__("item_entry.paper.total")}
|
||||||
tbody
|
tbody
|
||||||
each line in lines
|
each entry in creditNote.entries
|
||||||
tr(class=`${prefix}-table__row`)
|
tr
|
||||||
td(class=`${prefix}-table__cell ${prefix}-table__cell--item ${prefix}-table__cell--item`)
|
td.item
|
||||||
div.item
|
div.title=entry.item.name
|
||||||
div.item__label #{line.item}
|
span.description=entry.description
|
||||||
div.item__description #{line.description}
|
td.rate=entry.rate
|
||||||
td(class=`${prefix}-table__cell ${prefix}-table__cell--quantity ${prefix}-table__cell--right`) #{line.quantity}
|
td.quantity=entry.quantity
|
||||||
td(class=`${prefix}-table__cell ${prefix}-table__cell--rate ${prefix}-table__cell--right`) #{line.rate}
|
td.total=entry.amount
|
||||||
td(class=`${prefix}-table__cell ${prefix}-table__cell--total ${prefix}-table__cell--right`) #{line.total}
|
|
||||||
|
|
||||||
div(class=`${prefix}-totals`)
|
div.credit__table-after
|
||||||
if showSubtotal
|
div.credit__table-total
|
||||||
div(class=`${prefix}-totals__item ${prefix}-totals__item--border-gray`)
|
table
|
||||||
div(class=`${prefix}-totals__item-label`) #{subtotallabel}
|
tbody
|
||||||
div(class=`${prefix}-totals__item-amount`) #{subtotal}
|
tr.total
|
||||||
|
td #{__('credit.paper.total')}
|
||||||
|
td #{creditNote.formattedAmount}
|
||||||
|
tr.payment-amount
|
||||||
|
td #{__('credit.paper.credits_used')}
|
||||||
|
td #{creditNote.formattedCreditsUsed}
|
||||||
|
tr.blanace-due
|
||||||
|
td #{__('credit.paper.credits_remaining')}
|
||||||
|
td #{creditNote.formattedCreditsRemaining}
|
||||||
|
|
||||||
if showTotal
|
div.credit__footer
|
||||||
div(class=`${prefix}-totals__item ${prefix}-totals__item--border-dark`)
|
if creditNote.termsConditions
|
||||||
div(class=`${prefix}-totals__item-amount`) #{totalLabel}:
|
div.credit__conditions
|
||||||
div(class=`${prefix}-totals__item-label`) #{total}
|
h3 #{__("credit.paper.terms_conditions")}
|
||||||
|
p #{creditNote.termsConditions}
|
||||||
|
|
||||||
if showCustomerNote && customerNote
|
if creditNote.note
|
||||||
div(class=`${prefix}-statement`)
|
div.credit__notes
|
||||||
div(class=`${prefix}-statement__label`) #{customerNoteLabel}:
|
h3 #{__("credit.paper.notes")}
|
||||||
div(class=`${prefix}-statement__value`) #{customerNote}
|
p #{creditNote.note}
|
||||||
|
|
||||||
if showTermsConditions && termsConditions
|
|
||||||
div(class=`${prefix}-statement`)
|
|
||||||
div(class=`${prefix}-statement__label`) #{termsConditionsLabel}:
|
|
||||||
div(class=`${prefix}-statement__value`) #{termsConditions}
|
|
||||||
82
packages/server/resources/views/modules/estimate-regular.pug
Normal file
82
packages/server/resources/views/modules/estimate-regular.pug
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
extends ../PaperTemplateLayout.pug
|
||||||
|
|
||||||
|
block head
|
||||||
|
style
|
||||||
|
if (isRtl)
|
||||||
|
include ../../css/modules/estimate-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/estimate.css
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.estimate
|
||||||
|
div.estimate__header
|
||||||
|
div.paper
|
||||||
|
h1.title #{__("estimate.paper.estimate")}
|
||||||
|
span.email #{saleEstimate.estimateNumber}
|
||||||
|
|
||||||
|
div.organization
|
||||||
|
h3.title #{organizationName}
|
||||||
|
if organizationEmail
|
||||||
|
span.email #{organizationEmail}
|
||||||
|
|
||||||
|
div.estimate__estimate-amount
|
||||||
|
div.label #{__('estimate.paper.estimate_amount')}
|
||||||
|
div.amount #{saleEstimate.formattedAmount}
|
||||||
|
|
||||||
|
div.estimate__meta
|
||||||
|
if saleEstimate.estimateNumber
|
||||||
|
div.estimate__meta-item.estimate__meta-item--estimate-number
|
||||||
|
span.label #{__("estimate.paper.estimate_number")}
|
||||||
|
span.value #{saleEstimate.estimateNumber}
|
||||||
|
|
||||||
|
div.estimate__meta-item.estimate__meta-item--billed-to
|
||||||
|
span.label #{__("estimate.paper.billed_to")}
|
||||||
|
span.value #{saleEstimate.customer.displayName}
|
||||||
|
|
||||||
|
div.estimate__meta-item.estimate__meta-item--estimate-date
|
||||||
|
span.label #{__("estimate.paper.estimate_date")}
|
||||||
|
span.value #{saleEstimate.formattedEstimateDate}
|
||||||
|
|
||||||
|
div.estimate__meta-item.estimate__meta-item--due-date
|
||||||
|
span.label #{__("estimate.paper.expiration_date")}
|
||||||
|
span.value #{saleEstimate.formattedExpirationDate}
|
||||||
|
|
||||||
|
div.estimate__table
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th.item #{__("item_entry.paper.item_name")}
|
||||||
|
th.rate #{__("item_entry.paper.rate")}
|
||||||
|
th.quantity #{__("item_entry.paper.quantity")}
|
||||||
|
th.total #{__("item_entry.paper.total")}
|
||||||
|
tbody
|
||||||
|
each entry in saleEstimate.entries
|
||||||
|
tr
|
||||||
|
td.item
|
||||||
|
div.title=entry.item.name
|
||||||
|
span.description=entry.description
|
||||||
|
td.rate=entry.rate
|
||||||
|
td.quantity=entry.quantity
|
||||||
|
td.total=entry.amount
|
||||||
|
|
||||||
|
div.estimate__table-after
|
||||||
|
div.estimate__table-total
|
||||||
|
table
|
||||||
|
tbody
|
||||||
|
tr.subtotal
|
||||||
|
td #{__('estimate.paper.subtotal')}
|
||||||
|
td #{saleEstimate.formattedAmount}
|
||||||
|
tr.total
|
||||||
|
td #{__('estimate.paper.total')}
|
||||||
|
td #{saleEstimate.formattedAmount}
|
||||||
|
|
||||||
|
div.estimate__footer
|
||||||
|
if saleEstimate.termsConditions
|
||||||
|
div.estimate__conditions
|
||||||
|
h3 #{__("estimate.paper.conditions_title")}
|
||||||
|
p #{saleEstimate.termsConditions}
|
||||||
|
|
||||||
|
if saleEstimate.note
|
||||||
|
div.estimate__notes
|
||||||
|
h3 #{__("estimate.paper.notes_title")}
|
||||||
|
p #{saleEstimate.note}
|
||||||
92
packages/server/resources/views/modules/invoice-regular.pug
Normal file
92
packages/server/resources/views/modules/invoice-regular.pug
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
extends ../PaperTemplateLayout.pug
|
||||||
|
|
||||||
|
block head
|
||||||
|
style
|
||||||
|
if (isRtl)
|
||||||
|
include ../../css/modules/invoice-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/invoice.css
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.invoice
|
||||||
|
div.invoice__header
|
||||||
|
div.paper
|
||||||
|
h1.title #{__("invoice.paper.invoice")}
|
||||||
|
if saleInvoice.invoiceNo
|
||||||
|
span.invoiceNo #{saleInvoice.invoiceNo}
|
||||||
|
|
||||||
|
div.organization
|
||||||
|
h3.title #{organizationName}
|
||||||
|
if organizationEmail
|
||||||
|
span.email #{organizationEmail}
|
||||||
|
|
||||||
|
div.invoice__due-amount
|
||||||
|
div.label #{__('invoice.paper.invoice_amount')}
|
||||||
|
div.amount #{saleInvoice.totalFormatted}
|
||||||
|
|
||||||
|
div.invoice__meta
|
||||||
|
div.invoice__meta-item.invoice__meta-item--amount
|
||||||
|
span.label #{__('invoice.paper.due_amount')}
|
||||||
|
span.value #{saleInvoice.dueAmountFormatted}
|
||||||
|
|
||||||
|
div.invoice__meta-item.invoice__meta-item--billed-to
|
||||||
|
span.label #{__("invoice.paper.billed_to")}
|
||||||
|
span.value #{saleInvoice.customer.displayName}
|
||||||
|
|
||||||
|
div.invoice__meta-item.invoice__meta-item--invoice-date
|
||||||
|
span.label #{__("invoice.paper.invoice_date")}
|
||||||
|
span.value #{saleInvoice.invoiceDateFormatted}
|
||||||
|
|
||||||
|
div.invoice__meta-item.invoice__meta-item--due-date
|
||||||
|
span.label #{__("invoice.paper.due_date")}
|
||||||
|
span.value #{saleInvoice.dueDateFormatted}
|
||||||
|
|
||||||
|
div.invoice__table
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th.item #{__("item_entry.paper.item_name")}
|
||||||
|
th.rate #{__("item_entry.paper.rate")}
|
||||||
|
th.quantity #{__("item_entry.paper.quantity")}
|
||||||
|
th.total #{__("item_entry.paper.total")}
|
||||||
|
tbody
|
||||||
|
each entry in saleInvoice.entries
|
||||||
|
tr
|
||||||
|
td.item
|
||||||
|
div.title=entry.item.name
|
||||||
|
span.description=entry.description
|
||||||
|
td.rate=entry.rate
|
||||||
|
td.quantity=entry.quantity
|
||||||
|
td.total=entry.amount
|
||||||
|
|
||||||
|
div.invoice__table-after
|
||||||
|
div.invoice__table-total
|
||||||
|
table
|
||||||
|
tbody
|
||||||
|
tr.subtotal
|
||||||
|
td #{__('invoice.paper.subtotal')}
|
||||||
|
td #{saleInvoice.subtotalFormatted}
|
||||||
|
each tax in saleInvoice.taxes
|
||||||
|
tr.tax_line
|
||||||
|
td #{tax.name} [#{tax.taxRate}%]
|
||||||
|
td #{tax.taxRateAmountFormatted}
|
||||||
|
tr.total
|
||||||
|
td #{__('invoice.paper.total')}
|
||||||
|
td #{saleInvoice.totalFormatted}
|
||||||
|
tr.payment-amount
|
||||||
|
td #{__('invoice.paper.payment_amount')}
|
||||||
|
td #{saleInvoice.paymentAmountFormatted}
|
||||||
|
tr.blanace-due
|
||||||
|
td #{__('invoice.paper.balance_due')}
|
||||||
|
td #{saleInvoice.dueAmountFormatted}
|
||||||
|
|
||||||
|
div.invoice__footer
|
||||||
|
if saleInvoice.termsConditions
|
||||||
|
div.invoice__conditions
|
||||||
|
h3 #{__("invoice.paper.conditions_title")}
|
||||||
|
p #{saleInvoice.termsConditions}
|
||||||
|
|
||||||
|
if saleInvoice.invoiceMessage
|
||||||
|
div.invoice__notes
|
||||||
|
h3 #{__("invoice.paper.notes_title")}
|
||||||
|
p #{saleInvoice.invoiceMessage}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
extends ../PaperTemplateLayout.pug
|
||||||
|
|
||||||
|
block head
|
||||||
|
style
|
||||||
|
if (isRtl)
|
||||||
|
include ../../css/modules/payment-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/payment.css
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.payment
|
||||||
|
div.payment__header
|
||||||
|
div.paper
|
||||||
|
h1.title #{__("payment.paper.payment_receipt")}
|
||||||
|
if paymentReceive.paymentReceiveNo
|
||||||
|
span.paymentNumber #{paymentReceive.paymentReceiveNo}
|
||||||
|
|
||||||
|
div.organization
|
||||||
|
h3.title #{organizationName}
|
||||||
|
if organizationEmail
|
||||||
|
span.email #{organizationEmail}
|
||||||
|
|
||||||
|
div.payment__received-amount
|
||||||
|
div.label #{__('payment.paper.amount_received')}
|
||||||
|
div.amount #{paymentReceive.formattedAmount}
|
||||||
|
|
||||||
|
div.payment__meta
|
||||||
|
div.payment__meta-item.payment__meta-item--billed-to
|
||||||
|
span.label #{__("payment.paper.billed_to")}
|
||||||
|
span.value #{paymentReceive.customer.displayName}
|
||||||
|
|
||||||
|
div.payment__meta-item.payment__meta-item--payment-date
|
||||||
|
span.label #{__("payment.paper.payment_date")}
|
||||||
|
span.value #{paymentReceive.formattedPaymentDate}
|
||||||
|
|
||||||
|
div.payment__table
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th.item #{__("payment.paper.invoice_number")}
|
||||||
|
th.date #{__("payment.paper.invoice_date")}
|
||||||
|
th.invoiceAmount #{__("payment.paper.invoice_amount")}
|
||||||
|
th.paymentAmount #{__("payment.paper.payment_amount")}
|
||||||
|
tbody
|
||||||
|
each entry in paymentReceive.entries
|
||||||
|
tr
|
||||||
|
td.item=entry.invoice.invoiceNo
|
||||||
|
td.date=entry.invoice.invoiceDateFormatted
|
||||||
|
td.invoiceAmount=entry.invoice.totalFormatted
|
||||||
|
td.paymentAmount=entry.invoice.paymentAmountFormatted
|
||||||
|
|
||||||
|
div.payment__table-after
|
||||||
|
div.payment__table-total
|
||||||
|
table
|
||||||
|
tbody
|
||||||
|
tr.payment-amount
|
||||||
|
td #{__('payment.paper.payment_amount')}
|
||||||
|
td #{paymentReceive.formattedAmount}
|
||||||
|
tr.blanace-due
|
||||||
|
td #{__('payment.paper.balance_due')}
|
||||||
|
td #{paymentReceive.customer.closingBalance}
|
||||||
|
|
||||||
|
div.payment__footer
|
||||||
|
if paymentReceive.statement
|
||||||
|
div.payment__notes
|
||||||
|
h3 #{__("payment.paper.statement")}
|
||||||
|
p #{paymentReceive.statement}
|
||||||
77
packages/server/resources/views/modules/receipt-regular.pug
Normal file
77
packages/server/resources/views/modules/receipt-regular.pug
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
extends ../PaperTemplateLayout.pug
|
||||||
|
|
||||||
|
block head
|
||||||
|
style
|
||||||
|
if (isRtl)
|
||||||
|
include ../../css/modules/receipt-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/receipt.css
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.receipt
|
||||||
|
div.receipt__header
|
||||||
|
div.paper
|
||||||
|
h1.title #{__("receipt.paper.receipt")}
|
||||||
|
span.receiptNumber #{saleReceipt.receiptNumber}
|
||||||
|
|
||||||
|
div.organization
|
||||||
|
h3.title #{organizationName}
|
||||||
|
|
||||||
|
div.receipt__receipt-amount
|
||||||
|
div.label #{__('receipt.paper.receipt_amount')}
|
||||||
|
div.amount #{saleReceipt.formattedAmount}
|
||||||
|
|
||||||
|
div.receipt__meta
|
||||||
|
div.receipt__meta-item.receipt__meta-item--billed-to
|
||||||
|
span.label #{__("receipt.paper.billed_to")}
|
||||||
|
span.value #{saleReceipt.customer.displayName}
|
||||||
|
|
||||||
|
div.receipt__meta-item.receipt__meta-item--invoice-date
|
||||||
|
span.label #{__("receipt.paper.receipt_date")}
|
||||||
|
span.value #{saleReceipt.formattedReceiptDate}
|
||||||
|
|
||||||
|
if saleReceipt.receiptNumber
|
||||||
|
div.receipt__meta-item.receipt__meta-item--invoice-number
|
||||||
|
span.label #{__("receipt.paper.receipt_number")}
|
||||||
|
span.value #{saleReceipt.receiptNumber}
|
||||||
|
|
||||||
|
div.receipt__table
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th.item #{__("item_entry.paper.item_name")}
|
||||||
|
th.rate #{__("item_entry.paper.rate")}
|
||||||
|
th.quantity #{__("item_entry.paper.quantity")}
|
||||||
|
th.total #{__("item_entry.paper.total")}
|
||||||
|
tbody
|
||||||
|
each entry in saleReceipt.entries
|
||||||
|
tr
|
||||||
|
td.item=entry.item.name
|
||||||
|
td.rate=entry.rate
|
||||||
|
td.quantity=entry.quantity
|
||||||
|
td.total=entry.amount
|
||||||
|
|
||||||
|
div.receipt__table-after
|
||||||
|
div.receipt__table-total
|
||||||
|
table
|
||||||
|
tbody
|
||||||
|
tr.total
|
||||||
|
td #{__('receipt.paper.total')}
|
||||||
|
td #{saleReceipt.formattedAmount}
|
||||||
|
tr.payment-amount
|
||||||
|
td #{__('receipt.paper.payment_amount')}
|
||||||
|
td #{saleReceipt.formattedAmount}
|
||||||
|
tr.blanace-due
|
||||||
|
td #{__('receipt.paper.balance_due')}
|
||||||
|
td #{'$0'}
|
||||||
|
|
||||||
|
div.receipt__footer
|
||||||
|
if saleReceipt.statement
|
||||||
|
div.receipt__conditions
|
||||||
|
h3 #{__("receipt.paper.statement")}
|
||||||
|
p #{saleReceipt.statement}
|
||||||
|
|
||||||
|
if saleReceipt.receiptMessage
|
||||||
|
div.receipt__notes
|
||||||
|
h3 #{__("receipt.paper.notes")}
|
||||||
|
p #{saleReceipt.receiptMessage}
|
||||||
@@ -5,7 +5,14 @@ import { body, param } from 'express-validator';
|
|||||||
import BaseController from '@/api/controllers/BaseController';
|
import BaseController from '@/api/controllers/BaseController';
|
||||||
import { AttachmentsApplication } from '@/services/Attachments/AttachmentsApplication';
|
import { AttachmentsApplication } from '@/services/Attachments/AttachmentsApplication';
|
||||||
import { AttachmentUploadPipeline } from '@/services/Attachments/S3UploadPipeline';
|
import { AttachmentUploadPipeline } from '@/services/Attachments/S3UploadPipeline';
|
||||||
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
ApiTags,
|
||||||
|
Route,
|
||||||
|
} from '@/decorators/swagger-decorators';
|
||||||
|
|
||||||
|
@ApiTags('Attachments')
|
||||||
@Service()
|
@Service()
|
||||||
export class AttachmentsController extends BaseController {
|
export class AttachmentsController extends BaseController {
|
||||||
@Inject()
|
@Inject()
|
||||||
@@ -121,6 +128,26 @@ export class AttachmentsController extends BaseController {
|
|||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
* @returns {Promise<Response|void>}
|
* @returns {Promise<Response|void>}
|
||||||
*/
|
*/
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Details of the given attachement',
|
||||||
|
schema: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
email: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'Retrieve a specific details of attachment',
|
||||||
|
description: 'Get all registered users',
|
||||||
|
})
|
||||||
|
@Route('/attachments/:id')
|
||||||
private async getAttachment(
|
private async getAttachment(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ import { IItemDTO, ItemAction, AbilitySubject } from '@/interfaces';
|
|||||||
import { DATATYPES_LENGTH } from '@/data/DataTypes';
|
import { DATATYPES_LENGTH } from '@/data/DataTypes';
|
||||||
import CheckAbilities from '@/api/middleware/CheckPolicies';
|
import CheckAbilities from '@/api/middleware/CheckPolicies';
|
||||||
import { ItemsApplication } from '@/services/Items/ItemsApplication';
|
import { ItemsApplication } from '@/services/Items/ItemsApplication';
|
||||||
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
Route,
|
||||||
|
} from '@/decorators/swagger-decorators';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class ItemsController extends BaseController {
|
export default class ItemsController extends BaseController {
|
||||||
@@ -198,6 +203,22 @@ export default class ItemsController extends BaseController {
|
|||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Details of the given attachement',
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'string' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'Creates a new item (inventory or service)',
|
||||||
|
description: 'Get all registered users',
|
||||||
|
})
|
||||||
|
@Route('/items')
|
||||||
private async newItem(req: Request, res: Response, next: NextFunction) {
|
private async newItem(req: Request, res: Response, next: NextFunction) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const itemDTO: IItemDTO = this.matchedBodyData(req);
|
const itemDTO: IItemDTO = this.matchedBodyData(req);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import BaseController from '@/api/controllers/BaseController';
|
|||||||
@Service()
|
@Service()
|
||||||
export default class OrganizationController extends BaseController {
|
export default class OrganizationController extends BaseController {
|
||||||
@Inject()
|
@Inject()
|
||||||
private organizationService: OrganizationService;
|
organizationService: OrganizationService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
@@ -56,10 +56,10 @@ export default class OrganizationController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build organization validation schema.
|
* Organization setup schema.
|
||||||
* @returns {ValidationChain[]}
|
* @return {ValidationChain[]}
|
||||||
*/
|
*/
|
||||||
private get buildOrganizationValidationSchema(): ValidationChain[] {
|
private get commonOrganizationValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
check('name').exists().trim(),
|
check('name').exists().trim(),
|
||||||
check('industry').optional({ nullable: true }).isString().trim(),
|
check('industry').optional({ nullable: true }).isString().trim(),
|
||||||
@@ -72,34 +72,21 @@ export default class OrganizationController extends BaseController {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build organization validation schema.
|
||||||
|
* @returns {ValidationChain[]}
|
||||||
|
*/
|
||||||
|
private get buildOrganizationValidationSchema(): ValidationChain[] {
|
||||||
|
return [...this.commonOrganizationValidationSchema];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update organization validation schema.
|
* Update organization validation schema.
|
||||||
* @returns {ValidationChain[]}
|
* @returns {ValidationChain[]}
|
||||||
*/
|
*/
|
||||||
private get updateOrganizationValidationSchema(): ValidationChain[] {
|
private get updateOrganizationValidationSchema(): ValidationChain[] {
|
||||||
return [
|
return [
|
||||||
// # Profile
|
...this.commonOrganizationValidationSchema,
|
||||||
check('name').optional().trim(),
|
|
||||||
check('industry').optional({ nullable: true }).isString().trim(),
|
|
||||||
check('location').optional().isString().isISO31661Alpha2(),
|
|
||||||
check('base_currency').optional().isISO4217(),
|
|
||||||
check('timezone').optional().isIn(moment.tz.names()),
|
|
||||||
check('fiscal_year').optional().isIn(MONTHS),
|
|
||||||
check('language').optional().isString().isIn(ACCEPTED_LOCALES),
|
|
||||||
check('date_format').optional().isIn(DATE_FORMATS),
|
|
||||||
|
|
||||||
// # Address
|
|
||||||
check('address.address_1').optional().isString().trim(),
|
|
||||||
check('address.address_2').optional().isString().trim(),
|
|
||||||
check('address.postal_code').optional().isString().trim(),
|
|
||||||
check('address.city').optional().isString().trim(),
|
|
||||||
check('address.state_province').optional().isString().trim(),
|
|
||||||
check('address.phone').optional().isString().trim(),
|
|
||||||
|
|
||||||
// # Branding
|
|
||||||
check('primary_color').optional({ nullable: true }).isHexColor().trim(),
|
|
||||||
check('logo_key').optional({ nullable: true }).isString().trim(),
|
|
||||||
|
|
||||||
check('tax_number').optional({ nullable: true }).isString().trim(),
|
check('tax_number').optional({ nullable: true }).isString().trim(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -169,7 +156,7 @@ export default class OrganizationController extends BaseController {
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const tenantDTO = this.matchedBodyData(req, { includeOptionals: false });
|
const tenantDTO = this.matchedBodyData(req);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.organizationService.updateOrganization(tenantId, tenantDTO);
|
await this.organizationService.updateOrganization(tenantId, tenantDTO);
|
||||||
|
|||||||
@@ -1,179 +0,0 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import { Request, Response, Router, NextFunction } from 'express';
|
|
||||||
import { body, param } from 'express-validator';
|
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { PaymentServicesApplication } from '@/services/PaymentServices/PaymentServicesApplication';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class PaymentServicesController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private paymentServicesApp: PaymentServicesApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/',
|
|
||||||
asyncMiddleware(this.getPaymentServicesSpecificInvoice.bind(this))
|
|
||||||
);
|
|
||||||
router.get('/state', this.getPaymentMethodsState.bind(this));
|
|
||||||
router.get('/:paymentServiceId', this.getPaymentService.bind(this));
|
|
||||||
router.post(
|
|
||||||
'/:paymentMethodId',
|
|
||||||
[
|
|
||||||
param('paymentMethodId').exists(),
|
|
||||||
|
|
||||||
body('name').optional().isString(),
|
|
||||||
body('options.bank_account_id').optional().isNumeric(),
|
|
||||||
body('options.clearing_account_id').optional().isNumeric(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
asyncMiddleware(this.updatePaymentMethod.bind(this))
|
|
||||||
);
|
|
||||||
router.delete(
|
|
||||||
'/:paymentMethodId',
|
|
||||||
[param('paymentMethodId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.deletePaymentMethod.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve accounts types list.
|
|
||||||
* @param {Request} req - Request.
|
|
||||||
* @param {Response} res - Response.
|
|
||||||
* @return {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
private async getPaymentServicesSpecificInvoice(
|
|
||||||
req: Request<{ invoiceId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const paymentServices =
|
|
||||||
await this.paymentServicesApp.getPaymentServicesForInvoice(tenantId);
|
|
||||||
|
|
||||||
return res.status(200).send({ paymentServices });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a specific payment service.
|
|
||||||
* @param {Request} req - Request.
|
|
||||||
* @param {Response} res - Response.
|
|
||||||
* @param {NextFunction} next - Next function.
|
|
||||||
* @return {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
private async getPaymentService(
|
|
||||||
req: Request<{ paymentServiceId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { paymentServiceId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const paymentService = await this.paymentServicesApp.getPaymentService(
|
|
||||||
tenantId,
|
|
||||||
paymentServiceId
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).send({ data: paymentService });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edits the given payment method settings.
|
|
||||||
* @param {Request} req - Request.
|
|
||||||
* @param {Response} res - Response.
|
|
||||||
* @return {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
private async updatePaymentMethod(
|
|
||||||
req: Request<{ paymentMethodId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { paymentMethodId } = req.params;
|
|
||||||
const updatePaymentMethodDTO = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.paymentServicesApp.editPaymentMethod(
|
|
||||||
tenantId,
|
|
||||||
paymentMethodId,
|
|
||||||
updatePaymentMethodDTO
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
id: paymentMethodId,
|
|
||||||
message: 'The given payment method has been updated.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the payment state providing state.
|
|
||||||
* @param {Request} req - Request.
|
|
||||||
* @param {Response} res - Response.
|
|
||||||
* @param {NextFunction} next - Next function.
|
|
||||||
* @return {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
private async getPaymentMethodsState(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const paymentMethodsState =
|
|
||||||
await this.paymentServicesApp.getPaymentMethodsState(tenantId);
|
|
||||||
|
|
||||||
return res.status(200).send({ data: paymentMethodsState });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the given payment method.
|
|
||||||
* @param {Request<{ paymentMethodId: number }>} req - Request.
|
|
||||||
* @param {Response} res - Response.
|
|
||||||
* @param {NextFunction} next - Next function.
|
|
||||||
* @return {Promise<Response | void>}
|
|
||||||
*/
|
|
||||||
private async deletePaymentMethod(
|
|
||||||
req: Request<{ paymentMethodId: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { paymentMethodId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.paymentServicesApp.deletePaymentMethod(
|
|
||||||
tenantId,
|
|
||||||
paymentMethodId
|
|
||||||
);
|
|
||||||
return res.status(204).send({
|
|
||||||
id: paymentMethodId,
|
|
||||||
message: 'The payment method has been deleted.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
import { Router, Request, Response, NextFunction } from 'express';
|
|
||||||
import { check, param, query } from 'express-validator';
|
|
||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { PdfTemplateApplication } from '@/services/PdfTemplate/PdfTemplateApplication';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class PdfTemplatesController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
public pdfTemplateApplication: PdfTemplateApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor method.
|
|
||||||
*/
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.delete(
|
|
||||||
'/:template_id',
|
|
||||||
[param('template_id').exists().isInt().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.deletePdfTemplate.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:template_id',
|
|
||||||
[
|
|
||||||
param('template_id').exists().isInt().toInt(),
|
|
||||||
check('template_name').exists(),
|
|
||||||
check('attributes').exists(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.editPdfTemplate.bind(this)
|
|
||||||
);
|
|
||||||
router.get('/state', this.getOrganizationBrandingState.bind(this));
|
|
||||||
router.get(
|
|
||||||
'/',
|
|
||||||
[query('resource').optional()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getPdfTemplates.bind(this)
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/:template_id',
|
|
||||||
[param('template_id').exists().isInt().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getPdfTemplate.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/',
|
|
||||||
[
|
|
||||||
check('template_name').exists(),
|
|
||||||
check('resource').exists(),
|
|
||||||
check('attributes').exists(),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.createPdfInvoiceTemplate.bind(this)
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:template_id/assign_default',
|
|
||||||
[param('template_id').exists().isInt().toInt()],
|
|
||||||
this.validationResult,
|
|
||||||
this.assginPdfTemplateAsDefault.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
async createPdfInvoiceTemplate(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { templateName, resource, attributes } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await this.pdfTemplateApplication.createPdfTemplate(
|
|
||||||
tenantId,
|
|
||||||
templateName,
|
|
||||||
resource,
|
|
||||||
attributes
|
|
||||||
);
|
|
||||||
return res.status(201).send({
|
|
||||||
id: result.id,
|
|
||||||
message: 'The PDF template has been created successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async editPdfTemplate(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { template_id: templateId } = req.params;
|
|
||||||
const editTemplateDTO = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await this.pdfTemplateApplication.editPdfTemplate(
|
|
||||||
tenantId,
|
|
||||||
Number(templateId),
|
|
||||||
editTemplateDTO
|
|
||||||
);
|
|
||||||
return res.status(200).send({
|
|
||||||
id: result.id,
|
|
||||||
message: 'The PDF template has been updated successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deletePdfTemplate(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { template_id: templateId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.pdfTemplateApplication.deletePdfTemplate(
|
|
||||||
tenantId,
|
|
||||||
Number(templateId)
|
|
||||||
);
|
|
||||||
return res.status(204).send({
|
|
||||||
id: templateId,
|
|
||||||
message: 'The PDF template has been deleted successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPdfTemplate(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { template_id: templateId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const template = await this.pdfTemplateApplication.getPdfTemplate(
|
|
||||||
tenantId,
|
|
||||||
Number(templateId)
|
|
||||||
);
|
|
||||||
return res.status(200).send(template);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPdfTemplates(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const query = this.matchedQueryData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const templates = await this.pdfTemplateApplication.getPdfTemplates(
|
|
||||||
tenantId,
|
|
||||||
query
|
|
||||||
);
|
|
||||||
return res.status(200).send(templates);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async assginPdfTemplateAsDefault(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { template_id: templateId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.pdfTemplateApplication.assignPdfTemplateAsDefault(
|
|
||||||
tenantId,
|
|
||||||
Number(templateId)
|
|
||||||
);
|
|
||||||
return res.status(204).send({
|
|
||||||
id: templateId,
|
|
||||||
message: 'The given pdf template has been assigned as default template',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async getOrganizationBrandingState(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data =
|
|
||||||
await this.pdfTemplateApplication.getPdfTemplateBrandingState(tenantId);
|
|
||||||
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import { check, param, query } from 'express-validator';
|
|||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
BillAction,
|
BillAction,
|
||||||
DiscountType,
|
|
||||||
IBillDTO,
|
IBillDTO,
|
||||||
IBillEditDTO,
|
IBillEditDTO,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
@@ -122,16 +121,11 @@ export default class BillsController extends BaseController {
|
|||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
|
||||||
.default(DiscountType.Percentage)
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description').optional({ nullable: true }).trim(),
|
||||||
check('entries.*.landed_cost')
|
check('entries.*.landed_cost')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
@@ -150,18 +144,8 @@ export default class BillsController extends BaseController {
|
|||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
|
||||||
// Attachments
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// # Discount
|
|
||||||
check('discount_type')
|
|
||||||
.default(DiscountType.Amount)
|
|
||||||
.isIn([DiscountType.Amount, DiscountType.Percentage]),
|
|
||||||
check('discount').optional({ nullable: true }).isDecimal().toFloat(),
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,15 +188,6 @@ export default class BillsController extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// # Discount
|
|
||||||
check('discount_type')
|
|
||||||
.default(DiscountType.Amount)
|
|
||||||
.isIn([DiscountType.Amount, DiscountType.Percentage]),
|
|
||||||
check('discount').optional({ nullable: true }).isDecimal().toFloat(),
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { check, param, query } from 'express-validator';
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
DiscountType,
|
|
||||||
IVendorCreditCreateDTO,
|
IVendorCreditCreateDTO,
|
||||||
IVendorCreditEditDTO,
|
IVendorCreditEditDTO,
|
||||||
VendorCreditAction,
|
VendorCreditAction,
|
||||||
@@ -171,15 +170,11 @@ export default class VendorCreditController extends BaseController {
|
|||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
|
||||||
.default(DiscountType.Percentage)
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description').optional({ nullable: true }).trim(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
@@ -188,16 +183,6 @@ export default class VendorCreditController extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Discount.
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.optional({ nullable: true })
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
// Adjustment.
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,15 +209,11 @@ export default class VendorCreditController extends BaseController {
|
|||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
|
||||||
.default(DiscountType.Percentage)
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description').optional({ nullable: true }).trim(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
@@ -241,16 +222,6 @@ export default class VendorCreditController extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Discount.
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.optional({ nullable: true })
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
// Adjustment.
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Inject, Service } from 'typedi';
|
|||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
CreditNoteAction,
|
CreditNoteAction,
|
||||||
DiscountType,
|
|
||||||
ICreditNoteEditDTO,
|
ICreditNoteEditDTO,
|
||||||
ICreditNoteNewDTO,
|
ICreditNoteNewDTO,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
@@ -28,7 +27,6 @@ import GetCreditNoteAssociatedAppliedInvoices from '@/services/CreditNotes/GetCr
|
|||||||
import GetRefundCreditTransaction from '@/services/CreditNotes/GetRefundCreditNoteTransaction';
|
import GetRefundCreditTransaction from '@/services/CreditNotes/GetRefundCreditNoteTransaction';
|
||||||
import GetCreditNotePdf from '../../../services/CreditNotes/GetCreditNotePdf';
|
import GetCreditNotePdf from '../../../services/CreditNotes/GetCreditNotePdf';
|
||||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
||||||
import { GetCreditNoteState } from '@/services/CreditNotes/GetCreditNoteState';
|
|
||||||
/**
|
/**
|
||||||
* Credit notes controller.
|
* Credit notes controller.
|
||||||
* @service
|
* @service
|
||||||
@@ -83,9 +81,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
@Inject()
|
@Inject()
|
||||||
creditNotePdf: GetCreditNotePdf;
|
creditNotePdf: GetCreditNotePdf;
|
||||||
|
|
||||||
@Inject()
|
|
||||||
getCreditNoteStateService: GetCreditNoteState;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router constructor.
|
* Router constructor.
|
||||||
*/
|
*/
|
||||||
@@ -110,12 +105,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
this.asyncMiddleware(this.newCreditNote),
|
this.asyncMiddleware(this.newCreditNote),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
'/state',
|
|
||||||
CheckPolicies(CreditNoteAction.View, AbilitySubject.CreditNote),
|
|
||||||
this.asyncMiddleware(this.getCreditNoteState.bind(this)),
|
|
||||||
this.handleServiceErrors
|
|
||||||
);
|
|
||||||
// Get specific credit note.
|
// Get specific credit note.
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
@@ -234,37 +223,19 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
|
||||||
.default(DiscountType.Percentage)
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description').optional({ nullable: true }).trim(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
|
||||||
// Attachments.
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Pdf template id.
|
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
|
||||||
|
|
||||||
// Discount.
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.optional({ nullable: true })
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
// Adjustment.
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,14 +458,13 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
ACCEPT_TYPE.APPLICATION_PDF,
|
ACCEPT_TYPE.APPLICATION_PDF,
|
||||||
]);
|
]);
|
||||||
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
|
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
|
||||||
const [pdfContent, filename] = await this.creditNotePdf.getCreditNotePdf(
|
const pdfContent = await this.creditNotePdf.getCreditNotePdf(
|
||||||
tenantId,
|
tenantId,
|
||||||
creditNoteId
|
creditNoteId
|
||||||
);
|
);
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'application/pdf',
|
'Content-Type': 'application/pdf',
|
||||||
'Content-Length': pdfContent.length,
|
'Content-Length': pdfContent.length,
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
});
|
||||||
res.send(pdfContent);
|
res.send(pdfContent);
|
||||||
} else {
|
} else {
|
||||||
@@ -763,23 +733,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private getCreditNoteState = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) => {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.getCreditNoteStateService.getCreditNoteState(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles service errors.
|
* Handles service errors.
|
||||||
* @param {Error} error
|
* @param {Error} error
|
||||||
|
|||||||
@@ -95,12 +95,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)),
|
asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
'/state',
|
|
||||||
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
|
|
||||||
this.getPaymentReceivedState.bind(this),
|
|
||||||
this.handleServiceErrors
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
|
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
|
||||||
@@ -130,18 +124,9 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
[
|
[
|
||||||
...this.paymentReceiveValidation,
|
...this.paymentReceiveValidation,
|
||||||
body('subject').isString().optional(),
|
body('subject').isString().optional(),
|
||||||
|
|
||||||
body('from').isString().optional(),
|
body('from').isString().optional(),
|
||||||
|
body('to').isString().optional(),
|
||||||
body('to').isArray().exists(),
|
body('body').isString().optional(),
|
||||||
body('to.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('cc').isArray().optional({ nullable: true }),
|
|
||||||
body('cc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('bcc').isArray().optional({ nullable: true }),
|
|
||||||
body('bcc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('attach_invoice').optional().isBoolean().toBoolean(),
|
body('attach_invoice').optional().isBoolean().toBoolean(),
|
||||||
],
|
],
|
||||||
this.sendPaymentReceiveByMail.bind(this),
|
this.sendPaymentReceiveByMail.bind(this),
|
||||||
@@ -182,9 +167,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// Pdf template id.
|
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,29 +388,6 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @async
|
|
||||||
* @param {Request} req -
|
|
||||||
* @param {Response} res -
|
|
||||||
*/
|
|
||||||
private async getPaymentReceivedState(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.paymentReceiveApplication.getPaymentReceivedState(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the given payment receive details.
|
* Retrieve the given payment receive details.
|
||||||
* @async
|
* @async
|
||||||
@@ -479,11 +438,10 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
const acceptType = accept.types([
|
const acceptType = accept.types([
|
||||||
ACCEPT_TYPE.APPLICATION_JSON,
|
ACCEPT_TYPE.APPLICATION_JSON,
|
||||||
ACCEPT_TYPE.APPLICATION_PDF,
|
ACCEPT_TYPE.APPLICATION_PDF,
|
||||||
ACCEPT_TYPE.APPLICATION_TEXT_HTML,
|
|
||||||
]);
|
]);
|
||||||
// Responds pdf format.
|
// Response in pdf format.
|
||||||
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
|
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
|
||||||
const [pdfContent, filename] =
|
const pdfContent =
|
||||||
await this.paymentReceiveApplication.getPaymentReceivePdf(
|
await this.paymentReceiveApplication.getPaymentReceivePdf(
|
||||||
tenantId,
|
tenantId,
|
||||||
paymentReceiveId
|
paymentReceiveId
|
||||||
@@ -491,18 +449,9 @@ export default class PaymentReceivesController extends BaseController {
|
|||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'application/pdf',
|
'Content-Type': 'application/pdf',
|
||||||
'Content-Length': pdfContent.length,
|
'Content-Length': pdfContent.length,
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
});
|
||||||
res.send(pdfContent);
|
res.send(pdfContent);
|
||||||
// Responds html format.
|
// Response in json format.
|
||||||
} else if (ACCEPT_TYPE.APPLICATION_TEXT_HTML === acceptType) {
|
|
||||||
const htmlContent =
|
|
||||||
await this.paymentReceiveApplication.getPaymentReceivedHtml(
|
|
||||||
tenantId,
|
|
||||||
paymentReceiveId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ htmlContent });
|
|
||||||
// Responds json format.
|
|
||||||
} else {
|
} else {
|
||||||
const paymentReceive =
|
const paymentReceive =
|
||||||
await this.paymentReceiveApplication.getPaymentReceive(
|
await this.paymentReceiveApplication.getPaymentReceive(
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { body, check, param, query } from 'express-validator';
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import {
|
import {
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
DiscountType,
|
|
||||||
ISaleEstimateDTO,
|
ISaleEstimateDTO,
|
||||||
SaleEstimateAction,
|
SaleEstimateAction,
|
||||||
SaleEstimateMailOptionsDTO,
|
SaleEstimateMailOptionsDTO,
|
||||||
@@ -14,8 +13,11 @@ import DynamicListingService from '@/services/DynamicListing/DynamicListService'
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { SaleEstimatesApplication } from '@/services/Sales/Estimates/SaleEstimatesApplication';
|
import { SaleEstimatesApplication } from '@/services/Sales/Estimates/SaleEstimatesApplication';
|
||||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
|
||||||
|
|
||||||
|
const ACCEPT_TYPE = {
|
||||||
|
APPLICATION_PDF: 'application/pdf',
|
||||||
|
APPLICATION_JSON: 'application/json',
|
||||||
|
};
|
||||||
@Service()
|
@Service()
|
||||||
export default class SalesEstimatesController extends BaseController {
|
export default class SalesEstimatesController extends BaseController {
|
||||||
@Inject()
|
@Inject()
|
||||||
@@ -49,7 +51,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
router.post(
|
router.post(
|
||||||
'/:id/approve',
|
'/:id/approve',
|
||||||
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
|
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
|
||||||
[...this.validateSpecificEstimateSchema],
|
[this.validateSpecificEstimateSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.approveSaleEstimate.bind(this)),
|
asyncMiddleware(this.approveSaleEstimate.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
@@ -57,7 +59,7 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
router.post(
|
router.post(
|
||||||
'/:id/reject',
|
'/:id/reject',
|
||||||
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
|
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
|
||||||
[...this.validateSpecificEstimateSchema],
|
[this.validateSpecificEstimateSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.rejectSaleEstimate.bind(this)),
|
asyncMiddleware(this.rejectSaleEstimate.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
@@ -103,12 +105,6 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
asyncMiddleware(this.deleteEstimate.bind(this)),
|
asyncMiddleware(this.deleteEstimate.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
'/state',
|
|
||||||
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
|
|
||||||
this.getSaleEstimateState.bind(this),
|
|
||||||
this.handleServiceErrors
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
|
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
|
||||||
@@ -131,18 +127,8 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
[
|
[
|
||||||
...this.validateSpecificEstimateSchema,
|
...this.validateSpecificEstimateSchema,
|
||||||
body('subject').isString().optional(),
|
body('subject').isString().optional(),
|
||||||
|
|
||||||
body('from').isString().optional(),
|
body('from').isString().optional(),
|
||||||
|
body('to').isString().optional(),
|
||||||
body('to').isArray().exists(),
|
|
||||||
body('to.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('cc').isArray().optional({ nullable: true }),
|
|
||||||
body('cc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('bcc').isArray().optional({ nullable: true }),
|
|
||||||
body('bcc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('body').isString().optional(),
|
body('body').isString().optional(),
|
||||||
body('attach_invoice').optional().isBoolean().toBoolean(),
|
body('attach_invoice').optional().isBoolean().toBoolean(),
|
||||||
],
|
],
|
||||||
@@ -151,10 +137,10 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/:id/mail/state',
|
'/:id/mail',
|
||||||
[...this.validateSpecificEstimateSchema],
|
[...this.validateSpecificEstimateSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getSaleEstimateMailState.bind(this)),
|
asyncMiddleware(this.getSaleEstimateMail.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
return router;
|
return router;
|
||||||
@@ -180,18 +166,15 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('entries').exists().isArray({ min: 1 }),
|
check('entries').exists().isArray({ min: 1 }),
|
||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
check('entries.*.description')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.trim(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
|
||||||
.default(DiscountType.Percentage)
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
@@ -201,21 +184,8 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
check('terms_conditions').optional().trim(),
|
check('terms_conditions').optional().trim(),
|
||||||
check('send_to_email').optional().trim(),
|
check('send_to_email').optional().trim(),
|
||||||
|
|
||||||
// # Attachments
|
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// # Pdf template id.
|
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
|
||||||
|
|
||||||
// # Discount
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.default(DiscountType.Amount)
|
|
||||||
.isIn([DiscountType.Amount, DiscountType.Percentage]),
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,30 +388,20 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
const acceptType = accept.types([
|
const acceptType = accept.types([
|
||||||
ACCEPT_TYPE.APPLICATION_JSON,
|
ACCEPT_TYPE.APPLICATION_JSON,
|
||||||
ACCEPT_TYPE.APPLICATION_PDF,
|
ACCEPT_TYPE.APPLICATION_PDF,
|
||||||
ACCEPT_TYPE.APPLICATION_TEXT_HTML,
|
|
||||||
]);
|
]);
|
||||||
// Retrieves estimate in pdf format.
|
// Retrieves estimate in pdf format.
|
||||||
if (ACCEPT_TYPE.APPLICATION_PDF == acceptType) {
|
if (ACCEPT_TYPE.APPLICATION_PDF == acceptType) {
|
||||||
const [pdfContent, filename] =
|
const pdfContent = await this.saleEstimatesApplication.getSaleEstimatePdf(
|
||||||
await this.saleEstimatesApplication.getSaleEstimatePdf(
|
tenantId,
|
||||||
tenantId,
|
estimateId
|
||||||
estimateId
|
);
|
||||||
);
|
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'application/pdf',
|
'Content-Type': 'application/pdf',
|
||||||
'Content-Length': pdfContent.length,
|
'Content-Length': pdfContent.length,
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
});
|
||||||
res.send(pdfContent);
|
res.send(pdfContent);
|
||||||
// Retrieves estimates in json format.
|
// Retrieves estimates in json format.
|
||||||
} else if (ACCEPT_TYPE.APPLICATION_TEXT_HTML === acceptType) {
|
} else {
|
||||||
const htmlContent =
|
|
||||||
await this.saleEstimatesApplication.getSaleEstimateHtml(
|
|
||||||
tenantId,
|
|
||||||
estimateId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ htmlContent });
|
|
||||||
} else if (ACCEPT_TYPE.APPLICATION_JSON) {
|
|
||||||
const estimate = await this.saleEstimatesApplication.getSaleEstimate(
|
const estimate = await this.saleEstimatesApplication.getSaleEstimate(
|
||||||
tenantId,
|
tenantId,
|
||||||
estimateId
|
estimateId
|
||||||
@@ -566,35 +526,18 @@ export default class SalesEstimatesController extends BaseController {
|
|||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
private getSaleEstimateMailState = async (
|
private getSaleEstimateMail = async (
|
||||||
req: Request<{ id: number }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) => {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { id: estimateId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.saleEstimatesApplication.getSaleEstimateMailState(
|
|
||||||
tenantId,
|
|
||||||
estimateId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private getSaleEstimateState = async (
|
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) => {
|
) => {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
|
const { id: invoiceId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await this.saleEstimatesApplication.getSaleEstimateState(
|
const data = await this.saleEstimatesApplication.getSaleEstimateMail(
|
||||||
tenantId
|
tenantId,
|
||||||
|
invoiceId
|
||||||
);
|
);
|
||||||
return res.status(200).send({ data });
|
return res.status(200).send({ data });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
SaleInvoiceAction,
|
SaleInvoiceAction,
|
||||||
AbilitySubject,
|
AbilitySubject,
|
||||||
SendInvoiceMailDTO,
|
SendInvoiceMailDTO,
|
||||||
DiscountType,
|
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { SaleInvoiceApplication } from '@/services/Sales/Invoices/SaleInvoicesApplication';
|
import { SaleInvoiceApplication } from '@/services/Sales/Invoices/SaleInvoicesApplication';
|
||||||
@@ -131,12 +130,6 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
this.asyncMiddleware(this.getInvoicePaymentTransactions),
|
this.asyncMiddleware(this.getInvoicePaymentTransactions),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
'/state',
|
|
||||||
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
|
|
||||||
asyncMiddleware(this.getSaleInvoiceState.bind(this)),
|
|
||||||
this.handleServiceErrors
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
|
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
|
||||||
@@ -145,7 +138,6 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
asyncMiddleware(this.getSaleInvoice.bind(this)),
|
asyncMiddleware(this.getSaleInvoice.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/',
|
'/',
|
||||||
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
|
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
|
||||||
@@ -180,21 +172,10 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
'/:id/mail',
|
'/:id/mail',
|
||||||
[
|
[
|
||||||
...this.specificSaleInvoiceValidation,
|
...this.specificSaleInvoiceValidation,
|
||||||
|
body('subject').isString().optional(),
|
||||||
body('subject').isString().optional({ nullable: true }),
|
|
||||||
body('message').isString().optional({ nullable: true }),
|
|
||||||
|
|
||||||
body('from').isString().optional(),
|
body('from').isString().optional(),
|
||||||
|
body('to').isString().optional(),
|
||||||
body('to').isArray().exists(),
|
body('body').isString().optional(),
|
||||||
body('to.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('cc').isArray().optional({ nullable: true }),
|
|
||||||
body('cc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('bcc').isArray().optional({ nullable: true }),
|
|
||||||
body('bcc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('attach_invoice').optional().isBoolean().toBoolean(),
|
body('attach_invoice').optional().isBoolean().toBoolean(),
|
||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
@@ -202,7 +183,7 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/:id/mail/state',
|
'/:id/mail',
|
||||||
[...this.specificSaleInvoiceValidation],
|
[...this.specificSaleInvoiceValidation],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getSaleInvoiceMail.bind(this)),
|
asyncMiddleware(this.getSaleInvoiceMail.bind(this)),
|
||||||
@@ -243,11 +224,9 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
check('entries.*.discount_type')
|
check('entries.*.description')
|
||||||
.default(DiscountType.Percentage)
|
.optional({ nullable: true })
|
||||||
.isString()
|
.trim(),
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
|
||||||
check('entries.*.tax_code')
|
check('entries.*.tax_code')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
@@ -278,24 +257,6 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toFloat(),
|
.toFloat(),
|
||||||
|
|
||||||
// Pdf template id.
|
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
|
||||||
|
|
||||||
// Payment methods.
|
|
||||||
check('payment_methods').optional({ nullable: true }).isArray(),
|
|
||||||
check('payment_methods.*.payment_integration_id').exists().toInt(),
|
|
||||||
check('payment_methods.*.enable').exists().isBoolean(),
|
|
||||||
|
|
||||||
// Discount
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.optional({ nullable: true })
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
// Adjustments
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,28 +425,19 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
const acceptType = accept.types([
|
const acceptType = accept.types([
|
||||||
ACCEPT_TYPE.APPLICATION_JSON,
|
ACCEPT_TYPE.APPLICATION_JSON,
|
||||||
ACCEPT_TYPE.APPLICATION_PDF,
|
ACCEPT_TYPE.APPLICATION_PDF,
|
||||||
ACCEPT_TYPE.APPLICATION_TEXT_HTML,
|
|
||||||
]);
|
]);
|
||||||
// Retrieves invoice in PDF format.
|
// Retrieves invoice in pdf format.
|
||||||
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
|
if (ACCEPT_TYPE.APPLICATION_PDF == acceptType) {
|
||||||
const [pdfContent, filename] =
|
const pdfContent = await this.saleInvoiceApplication.saleInvoicePdf(
|
||||||
await this.saleInvoiceApplication.saleInvoicePdf(
|
|
||||||
tenantId,
|
|
||||||
saleInvoiceId
|
|
||||||
);
|
|
||||||
res.set({
|
|
||||||
'Content-Type': 'application/pdf',
|
|
||||||
'Content-Length': pdfContent.length,
|
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
|
||||||
res.send(pdfContent);
|
|
||||||
// Retrieves invoice in html json format.
|
|
||||||
} else if (ACCEPT_TYPE.APPLICATION_TEXT_HTML === acceptType) {
|
|
||||||
const htmlContent = await this.saleInvoiceApplication.saleInvoiceHtml(
|
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceId
|
saleInvoiceId
|
||||||
);
|
);
|
||||||
return res.status(200).send({ htmlContent });
|
res.set({
|
||||||
|
'Content-Type': 'application/pdf',
|
||||||
|
'Content-Length': pdfContent.length,
|
||||||
|
});
|
||||||
|
res.send(pdfContent);
|
||||||
|
// Retrieves invoice in json format.
|
||||||
} else {
|
} else {
|
||||||
const saleInvoice = await this.saleInvoiceApplication.getSaleInvoice(
|
const saleInvoice = await this.saleInvoiceApplication.getSaleInvoice(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -495,24 +447,6 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
return res.status(200).send({ saleInvoice });
|
return res.status(200).send({ saleInvoice });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getSaleInvoiceState(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.saleInvoiceApplication.getSaleInvoiceState(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve paginated sales invoices with custom view metadata.
|
* Retrieve paginated sales invoices with custom view metadata.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
@@ -811,7 +745,7 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the mail state of the given sale invoice.
|
* Retrieves the default mail options of the given sale invoice.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
@@ -825,7 +759,7 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
const { id: invoiceId } = req.params;
|
const { id: invoiceId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await this.saleInvoiceApplication.getSaleInvoiceMailState(
|
const data = await this.saleInvoiceApplication.getSaleInvoiceMail(
|
||||||
tenantId,
|
tenantId,
|
||||||
invoiceId
|
invoiceId
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
import { AbilitySubject, DiscountType, SaleReceiptAction } from '@/interfaces';
|
import { AbilitySubject, SaleReceiptAction } from '@/interfaces';
|
||||||
import { SaleReceiptApplication } from '@/services/Sales/Receipts/SaleReceiptApplication';
|
import { SaleReceiptApplication } from '@/services/Sales/Receipts/SaleReceiptApplication';
|
||||||
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
import { ACCEPT_TYPE } from '@/interfaces/Http';
|
||||||
|
|
||||||
@@ -56,18 +56,8 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
[
|
[
|
||||||
...this.specificReceiptValidationSchema,
|
...this.specificReceiptValidationSchema,
|
||||||
body('subject').isString().optional(),
|
body('subject').isString().optional(),
|
||||||
|
|
||||||
body('from').isString().optional(),
|
body('from').isString().optional(),
|
||||||
|
body('to').isString().optional(),
|
||||||
body('to').isArray().exists(),
|
|
||||||
body('to.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('cc').isArray().optional({ nullable: true }),
|
|
||||||
body('cc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('bcc').isArray().optional({ nullable: true }),
|
|
||||||
body('bcc.*').isString().isEmail().optional(),
|
|
||||||
|
|
||||||
body('body').isString().optional(),
|
body('body').isString().optional(),
|
||||||
body('attach_receipt').optional().isBoolean().toBoolean(),
|
body('attach_receipt').optional().isBoolean().toBoolean(),
|
||||||
],
|
],
|
||||||
@@ -118,12 +108,6 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
this.handleServiceErrors,
|
this.handleServiceErrors,
|
||||||
this.dynamicListService.handlerErrorsToResponse
|
this.dynamicListService.handlerErrorsToResponse
|
||||||
);
|
);
|
||||||
router.get(
|
|
||||||
'/state',
|
|
||||||
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
|
|
||||||
asyncMiddleware(this.getSaleReceiptState.bind(this)),
|
|
||||||
this.handleServiceErrors
|
|
||||||
);
|
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
|
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
|
||||||
@@ -158,41 +142,23 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
|
check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
|
||||||
check('entries.*.index').exists().isNumeric().toInt(),
|
check('entries.*.index').exists().isNumeric().toInt(),
|
||||||
check('entries.*.item_id').exists().isNumeric().toInt(),
|
check('entries.*.item_id').exists().isNumeric().toInt(),
|
||||||
check('entries.*.quantity').exists().isNumeric().toFloat(),
|
check('entries.*.quantity').exists().isNumeric().toInt(),
|
||||||
check('entries.*.rate').exists().isNumeric().toFloat(),
|
check('entries.*.rate').exists().isNumeric().toFloat(),
|
||||||
check('entries.*.discount')
|
check('entries.*.discount')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
check('entries.*.discount_type')
|
check('entries.*.description')
|
||||||
.default(DiscountType.Percentage)
|
.optional({ nullable: true })
|
||||||
.isString()
|
.trim(),
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
check('entries.*.description').optional({ nullable: true }).trim(),
|
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
.toInt(),
|
.toInt(),
|
||||||
|
|
||||||
check('receipt_message').optional().trim(),
|
check('receipt_message').optional().trim(),
|
||||||
|
|
||||||
check('statement').optional().trim(),
|
check('statement').optional().trim(),
|
||||||
check('attachments').isArray().optional(),
|
check('attachments').isArray().optional(),
|
||||||
check('attachments.*.key').exists().isString(),
|
check('attachments.*.key').exists().isString(),
|
||||||
|
|
||||||
// # Pdf template
|
|
||||||
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
|
|
||||||
|
|
||||||
// # Discount
|
|
||||||
check('discount').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
check('discount_type')
|
|
||||||
.optional({ nullable: true })
|
|
||||||
.isString()
|
|
||||||
.isIn([DiscountType.Percentage, DiscountType.Amount]),
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,28 +344,19 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
const acceptType = accept.types([
|
const acceptType = accept.types([
|
||||||
ACCEPT_TYPE.APPLICATION_JSON,
|
ACCEPT_TYPE.APPLICATION_JSON,
|
||||||
ACCEPT_TYPE.APPLICATION_PDF,
|
ACCEPT_TYPE.APPLICATION_PDF,
|
||||||
ACCEPT_TYPE.APPLICATION_TEXT_HTML,
|
|
||||||
]);
|
]);
|
||||||
// Retrieves receipt in pdf format.
|
// Retrieves receipt in pdf format.
|
||||||
if (ACCEPT_TYPE.APPLICATION_PDF == acceptType) {
|
if (ACCEPT_TYPE.APPLICATION_PDF == acceptType) {
|
||||||
const [pdfContent, filename] =
|
const pdfContent = await this.saleReceiptsApplication.getSaleReceiptPdf(
|
||||||
await this.saleReceiptsApplication.getSaleReceiptPdf(
|
|
||||||
tenantId,
|
|
||||||
saleReceiptId
|
|
||||||
);
|
|
||||||
res.set({
|
|
||||||
'Content-Type': 'application/pdf',
|
|
||||||
'Content-Length': pdfContent.length,
|
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
|
||||||
res.send(pdfContent);
|
|
||||||
// Retrieves receipt in json format.
|
|
||||||
} else if (ACCEPT_TYPE.APPLICATION_TEXT_HTML === acceptType) {
|
|
||||||
const htmlContent = await this.saleReceiptsApplication.getSaleReceiptHtml(
|
|
||||||
tenantId,
|
tenantId,
|
||||||
saleReceiptId
|
saleReceiptId
|
||||||
);
|
);
|
||||||
res.send({ htmlContent });
|
res.set({
|
||||||
|
'Content-Type': 'application/pdf',
|
||||||
|
'Content-Length': pdfContent.length,
|
||||||
|
});
|
||||||
|
res.send(pdfContent);
|
||||||
|
// Retrieves receipt in json format.
|
||||||
} else {
|
} else {
|
||||||
const saleReceipt = await this.saleReceiptsApplication.getSaleReceipt(
|
const saleReceipt = await this.saleReceiptsApplication.getSaleReceipt(
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -409,30 +366,6 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
public async getSaleReceiptState(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
// Retrieves receipt in pdf format.
|
|
||||||
try {
|
|
||||||
const data = await this.saleReceiptsApplication.getSaleReceiptState(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sale receipt notification via SMS.
|
* Sale receipt notification via SMS.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
@@ -539,7 +472,7 @@ export default class SalesReceiptsController extends BaseController {
|
|||||||
const { id: receiptId } = req.params;
|
const { id: receiptId } = req.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await this.saleReceiptsApplication.getSaleReceiptMailState(
|
const data = await this.saleReceiptsApplication.getSaleReceiptMail(
|
||||||
tenantId,
|
tenantId,
|
||||||
receiptId
|
receiptId
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
|
||||||
import { param } from 'express-validator';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import { PaymentLinksApplication } from '@/services/PaymentLinks/PaymentLinksApplication';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class PublicSharableLinkController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private paymentLinkApp: PaymentLinksApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
'/:paymentLinkId/invoice',
|
|
||||||
[param('paymentLinkId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getPaymentLinkPublicMeta.bind(this),
|
|
||||||
this.validationResult
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
'/:paymentLinkId/invoice/pdf',
|
|
||||||
[param('paymentLinkId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.getPaymentLinkInvoicePdf.bind(this),
|
|
||||||
this.validationResult
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
'/:paymentLinkId/stripe_checkout_session',
|
|
||||||
[param('paymentLinkId').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.createInvoicePaymentLinkCheckoutSession.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the payment link public meta.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async getPaymentLinkPublicMeta(
|
|
||||||
req: Request<{ paymentLinkId: string }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { paymentLinkId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await this.paymentLinkApp.getInvoicePaymentLink(
|
|
||||||
paymentLinkId
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).send({ data });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Stripe checkout session for the given payment link id.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|void>}
|
|
||||||
*/
|
|
||||||
public async createInvoicePaymentLinkCheckoutSession(
|
|
||||||
req: Request<{ paymentLinkId: string }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { paymentLinkId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const session =
|
|
||||||
await this.paymentLinkApp.createInvoicePaymentCheckoutSession(
|
|
||||||
paymentLinkId
|
|
||||||
);
|
|
||||||
return res.status(200).send(session);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the sale invoice pdf of the given payment link.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
public async getPaymentLinkInvoicePdf(
|
|
||||||
req: Request<{ paymentLinkId: string }>,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { paymentLinkId } = req.params;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const [pdfContent, filename] =
|
|
||||||
await this.paymentLinkApp.getPaymentLinkInvoicePdf(paymentLinkId);
|
|
||||||
|
|
||||||
res.set({
|
|
||||||
'Content-Type': 'application/pdf',
|
|
||||||
'Content-Length': pdfContent.length,
|
|
||||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
|
||||||
});
|
|
||||||
res.send(pdfContent);
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
|
||||||
import { body } from 'express-validator';
|
|
||||||
import { AbilitySubject, PaymentReceiveAction } from '@/interfaces';
|
|
||||||
import BaseController from '@/api/controllers/BaseController';
|
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
|
||||||
import { GenerateShareLink } from '@/services/Sales/Invoices/GenerateeInvoicePaymentLink';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class ShareLinkController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private generateShareLinkService: GenerateShareLink;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/payment-links/generate',
|
|
||||||
CheckPolicies(PaymentReceiveAction.Edit, AbilitySubject.PaymentReceive),
|
|
||||||
[
|
|
||||||
body('transaction_type').exists(),
|
|
||||||
body('transaction_id').exists().isNumeric().toInt(),
|
|
||||||
body('publicity').optional(),
|
|
||||||
body('expiry_date').optional({ nullable: true }),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
asyncMiddleware(this.generateShareLink.bind(this))
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates sharable link for the given transaction.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
public async generateShareLink(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { transactionType, transactionId, publicity, expiryDate } =
|
|
||||||
this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const link = await this.generateShareLinkService.generatePaymentLink(
|
|
||||||
tenantId,
|
|
||||||
transactionId,
|
|
||||||
publicity,
|
|
||||||
expiryDate
|
|
||||||
);
|
|
||||||
res.status(200).json({ link });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import { body } from 'express-validator';
|
|
||||||
import { Service, Inject } from 'typedi';
|
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
|
||||||
import { StripePaymentApplication } from '@/services/StripePayment/StripePaymentApplication';
|
|
||||||
import BaseController from '../BaseController';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class StripeIntegrationController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
private stripePaymentApp: StripePaymentApplication;
|
|
||||||
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.get('/link', this.getStripeConnectLink.bind(this));
|
|
||||||
router.post(
|
|
||||||
'/callback',
|
|
||||||
[body('code').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
this.exchangeOAuth.bind(this)
|
|
||||||
);
|
|
||||||
router.post('/account', asyncMiddleware(this.createAccount.bind(this)));
|
|
||||||
router.post(
|
|
||||||
'/account_link',
|
|
||||||
[body('stripe_account_id').exists()],
|
|
||||||
this.validationResult,
|
|
||||||
asyncMiddleware(this.createAccountLink.bind(this))
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves Stripe OAuth2 connect link.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<Response|void>}
|
|
||||||
*/
|
|
||||||
public async getStripeConnectLink(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const authorizationUri = this.stripePaymentApp.getStripeConnectLink();
|
|
||||||
|
|
||||||
return res.status(200).send({ url: authorizationUri });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exchanges the given Stripe authorization code to Stripe user id and access token.
|
|
||||||
* @param {Request} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
public async exchangeOAuth(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { code } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.stripePaymentApp.exchangeStripeOAuthToken(tenantId, code);
|
|
||||||
|
|
||||||
return res.status(200).send({});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Stripe account.
|
|
||||||
* @param {Request} req - The Express request object.
|
|
||||||
* @param {Response} res - The Express response object.
|
|
||||||
* @param {NextFunction} next - The Express next middleware function.
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
public async createAccount(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const accountId = await this.stripePaymentApp.createStripeAccount(
|
|
||||||
tenantId
|
|
||||||
);
|
|
||||||
return res.status(201).json({
|
|
||||||
accountId,
|
|
||||||
message: 'The Stripe account has been created successfully.',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Stripe account session.
|
|
||||||
* @param {Request} req - The Express request object.
|
|
||||||
* @param {Response} res - The Express response object.
|
|
||||||
* @param {NextFunction} next - The Express next middleware function.
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
public async createAccountLink(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {
|
|
||||||
const { tenantId } = req;
|
|
||||||
const { stripeAccountId } = this.matchedBodyData(req);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clientSecret = await this.stripePaymentApp.createAccountLink(
|
|
||||||
tenantId,
|
|
||||||
stripeAccountId
|
|
||||||
);
|
|
||||||
return res.status(200).json({ clientSecret });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import { NextFunction, Request, Response, Router } from 'express';
|
|
||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import bodyParser from 'body-parser';
|
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
|
||||||
import { StripeWebhookEventPayload } from '@/interfaces/StripePayment';
|
|
||||||
import { StripePaymentService } from '@/services/StripePayment/StripePaymentService';
|
|
||||||
import events from '@/subscribers/events';
|
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class StripeWebhooksController {
|
|
||||||
@Inject()
|
|
||||||
private stripePaymentService: StripePaymentService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
private eventPublisher: EventPublisher;
|
|
||||||
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/stripe',
|
|
||||||
bodyParser.raw({ type: 'application/json' }),
|
|
||||||
this.handleWebhook.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles incoming Stripe webhook events.
|
|
||||||
* Verifies the webhook signature, processes the event based on its type,
|
|
||||||
* and triggers appropriate actions or events in the system.
|
|
||||||
*
|
|
||||||
* @param {Request} req - The Express request object containing the webhook payload.
|
|
||||||
* @param {Response} res - The Express response object.
|
|
||||||
* @param {NextFunction} next - The Express next middleware function.
|
|
||||||
*/
|
|
||||||
private async handleWebhook(req: Request, res: Response, next: NextFunction) {
|
|
||||||
try {
|
|
||||||
let event = req.body;
|
|
||||||
const sig = req.headers['stripe-signature'];
|
|
||||||
|
|
||||||
// Verify webhook signature and extract the event.
|
|
||||||
// See https://stripe.com/docs/webhooks#verify-events for more information.
|
|
||||||
try {
|
|
||||||
event = this.stripePaymentService.stripe.webhooks.constructEvent(
|
|
||||||
req.rawBody,
|
|
||||||
sig,
|
|
||||||
config.stripePayment.webhooksSecret
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
||||||
}
|
|
||||||
// Handle the event based on its type
|
|
||||||
switch (event.type) {
|
|
||||||
case 'checkout.session.completed':
|
|
||||||
// Triggers `onStripeCheckoutSessionCompleted` event.
|
|
||||||
this.eventPublisher.emitAsync(
|
|
||||||
events.stripeWebhooks.onCheckoutSessionCompleted,
|
|
||||||
{
|
|
||||||
event,
|
|
||||||
} as StripeWebhookEventPayload
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'account.updated':
|
|
||||||
this.eventPublisher.emitAsync(
|
|
||||||
events.stripeWebhooks.onAccountUpdated,
|
|
||||||
{
|
|
||||||
event,
|
|
||||||
} as StripeWebhookEventPayload
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
// Add more cases as needed
|
|
||||||
default:
|
|
||||||
console.log(`Unhandled event type ${event.type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json({ received: true });
|
|
||||||
} catch (error) {
|
|
||||||
next(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import { NextFunction, Router, Request, Response } from 'express';
|
import { NextFunction, Router, Request, Response } from 'express';
|
||||||
import Container, { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { PlaidApplication } from '@/services/Banking/Plaid/PlaidApplication';
|
import { PlaidApplication } from '@/services/Banking/Plaid/PlaidApplication';
|
||||||
import BaseController from '../BaseController';
|
import BaseController from '../BaseController';
|
||||||
import { LemonSqueezyWebhooks } from '@/services/Subscription/LemonSqueezyWebhooks';
|
import { LemonSqueezyWebhooks } from '@/services/Subscription/LemonSqueezyWebhooks';
|
||||||
import { PlaidWebhookTenantBootMiddleware } from '@/services/Banking/Plaid/PlaidWebhookTenantBootMiddleware';
|
import { PlaidWebhookTenantBootMiddleware } from '@/services/Banking/Plaid/PlaidWebhookTenantBootMiddleware';
|
||||||
import { StripeWebhooksController } from '../StripeIntegration/StripeWebhooksController';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class Webhooks extends BaseController {
|
export class Webhooks extends BaseController {
|
||||||
@@ -25,8 +24,6 @@ export class Webhooks extends BaseController {
|
|||||||
|
|
||||||
router.post('/lemon', this.lemonWebhooks.bind(this));
|
router.post('/lemon', this.lemonWebhooks.bind(this));
|
||||||
|
|
||||||
router.use(Container.get(StripeWebhooksController).router());
|
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,11 +64,6 @@ import { Webhooks } from './controllers/Webhooks/Webhooks';
|
|||||||
import { ExportController } from './controllers/Export/ExportController';
|
import { ExportController } from './controllers/Export/ExportController';
|
||||||
import { AttachmentsController } from './controllers/Attachments/AttachmentsController';
|
import { AttachmentsController } from './controllers/Attachments/AttachmentsController';
|
||||||
import { OneClickDemoController } from './controllers/OneClickDemo/OneClickDemoController';
|
import { OneClickDemoController } from './controllers/OneClickDemo/OneClickDemoController';
|
||||||
import { StripeIntegrationController } from './controllers/StripeIntegration/StripeIntegrationController';
|
|
||||||
import { ShareLinkController } from './controllers/ShareLink/ShareLinkController';
|
|
||||||
import { PublicSharableLinkController } from './controllers/ShareLink/PublicSharableLinkController';
|
|
||||||
import { PdfTemplatesController } from './controllers/PdfTemplates/PdfTemplatesController';
|
|
||||||
import { PaymentServicesController } from './controllers/PaymentServices/PaymentServicesController';
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const app = Router();
|
const app = Router();
|
||||||
@@ -86,11 +81,7 @@ export default () => {
|
|||||||
app.use('/jobs', Container.get(Jobs).router());
|
app.use('/jobs', Container.get(Jobs).router());
|
||||||
app.use('/account', Container.get(Account).router());
|
app.use('/account', Container.get(Account).router());
|
||||||
app.use('/webhooks', Container.get(Webhooks).router());
|
app.use('/webhooks', Container.get(Webhooks).router());
|
||||||
app.use('/demo', Container.get(OneClickDemoController).router());
|
app.use('/demo', Container.get(OneClickDemoController).router())
|
||||||
app.use(
|
|
||||||
'/payment-links',
|
|
||||||
Container.get(PublicSharableLinkController).router()
|
|
||||||
);
|
|
||||||
|
|
||||||
// - Dashboard routes.
|
// - Dashboard routes.
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
@@ -156,22 +147,10 @@ export default () => {
|
|||||||
dashboard.use('/import', Container.get(ImportController).router());
|
dashboard.use('/import', Container.get(ImportController).router());
|
||||||
dashboard.use('/export', Container.get(ExportController).router());
|
dashboard.use('/export', Container.get(ExportController).router());
|
||||||
dashboard.use('/attachments', Container.get(AttachmentsController).router());
|
dashboard.use('/attachments', Container.get(AttachmentsController).router());
|
||||||
dashboard.use(
|
|
||||||
'/stripe_integration',
|
|
||||||
Container.get(StripeIntegrationController).router()
|
|
||||||
);
|
|
||||||
dashboard.use(
|
|
||||||
'/pdf-templates',
|
|
||||||
Container.get(PdfTemplatesController).router()
|
|
||||||
);
|
|
||||||
dashboard.use(
|
|
||||||
'/payment-services',
|
|
||||||
Container.get(PaymentServicesController).router()
|
|
||||||
);
|
|
||||||
dashboard.use('/', Container.get(ProjectTasksController).router());
|
dashboard.use('/', Container.get(ProjectTasksController).router());
|
||||||
dashboard.use('/', Container.get(ProjectTimesController).router());
|
dashboard.use('/', Container.get(ProjectTimesController).router());
|
||||||
dashboard.use('/', Container.get(WarehousesItemController).router());
|
dashboard.use('/', Container.get(WarehousesItemController).router());
|
||||||
dashboard.use('/', Container.get(ShareLinkController).router());
|
|
||||||
|
|
||||||
dashboard.use('/dashboard', Container.get(DashboardController).router());
|
dashboard.use('/dashboard', Container.get(DashboardController).router());
|
||||||
dashboard.use('/', Container.get(Miscellaneous).router());
|
dashboard.use('/', Container.get(Miscellaneous).router());
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ export const injectI18nUtils = (req) => {
|
|||||||
export const initalizeTenantServices = async (tenantId: number) => {
|
export const initalizeTenantServices = async (tenantId: number) => {
|
||||||
const tenant = await Tenant.query()
|
const tenant = await Tenant.query()
|
||||||
.findById(tenantId)
|
.findById(tenantId)
|
||||||
.withGraphFetched('metadata')
|
.withGraphFetched('metadata');
|
||||||
.throwIfNotFound();
|
|
||||||
|
|
||||||
const tenantServices = Container.get(TenancyService);
|
const tenantServices = Container.get(TenancyService);
|
||||||
const tenantsManager = Container.get(TenantsManagerService);
|
const tenantsManager = Container.get(TenantsManagerService);
|
||||||
|
|||||||
@@ -259,17 +259,6 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
posthog: {
|
posthog: {
|
||||||
apiKey: process.env.POSTHOG_API_KEY,
|
apiKey: process.env.POSTHOG_API_KEY,
|
||||||
host: process.env.POSTHOG_HOST,
|
host: process.env.POSTHOG_HOST
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stripe Payment Integration.
|
|
||||||
*/
|
|
||||||
stripePayment: {
|
|
||||||
secretKey: process.env.STRIPE_PAYMENT_SECRET_KEY || '',
|
|
||||||
publishableKey: process.env.STRIPE_PAYMENT_PUBLISHABLE_KEY || '',
|
|
||||||
clientId: process.env.STRIPE_PAYMENT_CLIENT_ID || '',
|
|
||||||
redirectTo: process.env.STRIPE_PAYMENT_REDIRECT_URL || '',
|
|
||||||
webhooksSecret: process.env.STRIPE_PAYMENT_WEBHOOKS_SECRET || '',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,31 +1,15 @@
|
|||||||
export const SALE_INVOICE_CREATED = 'Sale invoice created';
|
export const SALE_INVOICE_CREATED = 'Sale invoice created';
|
||||||
export const SALE_INVOICE_EDITED = 'Sale invoice edited';
|
export const SALE_INVOICE_EDITED = 'Sale invoice d';
|
||||||
export const SALE_INVOICE_DELETED = 'Sale invoice deleted';
|
export const SALE_INVOICE_DELETED = 'Sale invoice deleted';
|
||||||
export const SALE_INVOICE_MAIL_DELIVERED = 'Sale invoice mail delivered';
|
export const SALE_INVOICE_MAIL_DELIVERED = 'Sale invoice mail delivered';
|
||||||
export const SALE_INVOICE_VIEWED = 'Sale invoice viewed';
|
|
||||||
export const SALE_INVOICE_PDF_VIEWED = 'Sale invoice PDF viewed';
|
|
||||||
export const SALE_INVOICE_MAIL_SENT = 'Sale invoice mail sent';
|
|
||||||
export const SALE_INVOICE_MAIL_REMINDER_SENT =
|
|
||||||
'Sale invoice reminder mail sent';
|
|
||||||
|
|
||||||
export const SALE_ESTIMATE_CREATED = 'Sale estimate created';
|
export const SALE_ESTIMATE_CREATED = 'Sale estimate created';
|
||||||
export const SALE_ESTIMATE_EDITED = 'Sale estimate edited';
|
export const SALE_ESTIMATE_EDITED = 'Sale estimate edited';
|
||||||
export const SALE_ESTIMATE_DELETED = 'Sale estimate deleted';
|
export const SALE_ESTIMATE_DELETED = 'Sale estimate deleted';
|
||||||
export const SALE_ESTIMATE_PDF_VIEWED = 'Sale estimate PDF viewed';
|
|
||||||
export const SALE_ESTIMATE_VIEWED = 'Sale estimate viewed';
|
|
||||||
export const SALE_ESTIMATE_MAIL_SENT = 'Sale estimate mail sent';
|
|
||||||
|
|
||||||
export const PAYMENT_RECEIVED_CREATED = 'Payment received created';
|
export const PAYMENT_RECEIVED_CREATED = 'Payment received created';
|
||||||
export const PAYMENT_RECEIVED_EDITED = 'payment received edited';
|
export const PAYMENT_RECEIVED_EDITED = 'payment received edited';
|
||||||
export const PAYMENT_RECEIVED_DELETED = 'Payment received deleted';
|
export const PAYMENT_RECEIVED_DELETED = 'Payment received deleted';
|
||||||
export const PAYMENT_RECEIVED_PDF_VIEWED = 'Payment received PDF viewed';
|
|
||||||
export const PAYMENT_RECEIVED_MAIL_SENT = 'Payment received mail sent';
|
|
||||||
|
|
||||||
export const SALE_RECEIPT_PDF_VIEWED = 'Sale credit PDF viewed';
|
|
||||||
export const SALE_RECEIPT_MAIL_SENT = 'Sale credit mail sent';
|
|
||||||
|
|
||||||
export const CREDIT_NOTE_PDF_VIEWED = 'Credit note PDF viewed';
|
|
||||||
export const CREDIT_NOTE_MAIL_SENT = 'Credit note mail sent';
|
|
||||||
|
|
||||||
export const BILL_CREATED = 'Bill created';
|
export const BILL_CREATED = 'Bill created';
|
||||||
export const BILL_EDITED = 'Bill edited';
|
export const BILL_EDITED = 'Bill edited';
|
||||||
@@ -42,12 +26,10 @@ export const EXPENSE_DELETED = 'Expense deleted';
|
|||||||
export const ACCOUNT_CREATED = 'Account created';
|
export const ACCOUNT_CREATED = 'Account created';
|
||||||
export const ACCOUNT_EDITED = 'Account Edited';
|
export const ACCOUNT_EDITED = 'Account Edited';
|
||||||
export const ACCOUNT_DELETED = 'Account deleted';
|
export const ACCOUNT_DELETED = 'Account deleted';
|
||||||
export const ACCOUNT_VIEWED = 'Account viewed';
|
|
||||||
|
|
||||||
export const ITEM_EVENT_CREATED = 'Item created';
|
export const ITEM_EVENT_CREATED = 'Item created';
|
||||||
export const ITEM_EVENT_EDITED = 'Item edited';
|
export const ITEM_EVENT_EDITED = 'Item edited';
|
||||||
export const ITEM_EVENT_DELETED = 'Item deleted';
|
export const ITEM_EVENT_DELETED = 'Item deleted';
|
||||||
export const ITEM_EVENT_VIEWED = 'Item viewed';
|
|
||||||
|
|
||||||
export const AUTH_SIGNED_UP = 'Auth Signed-up';
|
export const AUTH_SIGNED_UP = 'Auth Signed-up';
|
||||||
export const AUTH_RESET_PASSWORD = 'Auth reset password';
|
export const AUTH_RESET_PASSWORD = 'Auth reset password';
|
||||||
@@ -55,8 +37,6 @@ export const AUTH_RESET_PASSWORD = 'Auth reset password';
|
|||||||
export const SUBSCRIPTION_CANCELLED = 'Subscription cancelled';
|
export const SUBSCRIPTION_CANCELLED = 'Subscription cancelled';
|
||||||
export const SUBSCRIPTION_RESUMED = 'Subscription resumed';
|
export const SUBSCRIPTION_RESUMED = 'Subscription resumed';
|
||||||
export const SUBSCRIPTION_PLAN_CHANGED = 'Subscription plan changed';
|
export const SUBSCRIPTION_PLAN_CHANGED = 'Subscription plan changed';
|
||||||
export const SUBSCRIPTION_PAYMENT_SUCCEED = 'Subscription payment succeed';
|
|
||||||
export const SUBSCRIPTION_PAYMENT_FAILED = 'Subscription payment failed';
|
|
||||||
|
|
||||||
export const CUSTOMER_CREATED = 'Customer created';
|
export const CUSTOMER_CREATED = 'Customer created';
|
||||||
export const CUSTOMER_EDITED = 'Customer edited';
|
export const CUSTOMER_EDITED = 'Customer edited';
|
||||||
@@ -89,19 +69,6 @@ export const BANK_RULE_CREATED = 'Bank rule created';
|
|||||||
export const BANK_RULE_EDITED = 'Bank rule edited';
|
export const BANK_RULE_EDITED = 'Bank rule edited';
|
||||||
export const BANK_RULE_DELETED = 'Bank rule deleted';
|
export const BANK_RULE_DELETED = 'Bank rule deleted';
|
||||||
|
|
||||||
export const PDF_TEMPLATE_CREATED = 'PDF template created';
|
|
||||||
export const PDF_TEMPLATE_EDITED = 'PDF template edited';
|
|
||||||
export const PDF_TEMPLATE_DELETED = 'PDF template deleted';
|
|
||||||
export const PDF_TEMPLATE_ASSIGNED_DEFAULT = 'PDF template assigned as default';
|
|
||||||
|
|
||||||
export const PAYMENT_METHOD_EDITED = 'Payment method edited';
|
|
||||||
export const PAYMENT_METHOD_DELETED = 'Payment method deleted';
|
|
||||||
|
|
||||||
export const INVOICE_PAYMENT_LINK_GENERATED = 'Invoice payment link generated';
|
|
||||||
|
|
||||||
export const STRIPE_INTEGRAION_CONNECTED =
|
|
||||||
'Stripe integration oauth2 connected';
|
|
||||||
|
|
||||||
// # Event Groups
|
// # Event Groups
|
||||||
export const ACCOUNT_GROUP = 'Account';
|
export const ACCOUNT_GROUP = 'Account';
|
||||||
export const ITEM_GROUP = 'Item';
|
export const ITEM_GROUP = 'Item';
|
||||||
@@ -110,21 +77,3 @@ export const SALE_GROUP = 'Sale';
|
|||||||
export const PAYMENT_GROUP = 'Payment';
|
export const PAYMENT_GROUP = 'Payment';
|
||||||
export const BILL_GROUP = 'Bill';
|
export const BILL_GROUP = 'Bill';
|
||||||
export const EXPENSE_GROUP = 'Expense';
|
export const EXPENSE_GROUP = 'Expense';
|
||||||
|
|
||||||
// # Reports
|
|
||||||
export const BALANCE_SHEET_VIEWED = 'Balance sheet viewed';
|
|
||||||
export const TRIAL_BALANCE_SHEET_VIEWED = 'Trial balance sheet viewed';
|
|
||||||
export const PROFIT_LOSS_SHEET_VIEWED = 'Profit loss sheet viewed';
|
|
||||||
export const CASHFLOW_STATEMENT_VIEWED = 'Cashflow statement viewed';
|
|
||||||
export const GENERAL_LEDGER_VIEWED = 'General ledger viewed';
|
|
||||||
export const JOURNAL_VIEWED = 'Journal viewed';
|
|
||||||
export const RECEIVABLE_AGING_VIEWED = 'Receivable aging viewed';
|
|
||||||
export const PAYABLE_AGING_VIEWED = 'Payable aging viewed';
|
|
||||||
export const CUSTOMER_BALANCE_SUMMARY_VIEWED =
|
|
||||||
'Customer balance summary viewed';
|
|
||||||
export const VENDOR_BALANCE_SUMMARY_VIEWED = 'Vendor balance summary viewed';
|
|
||||||
export const INVENTORY_VALUATION_VIEWED = 'Inventory valuation viewed';
|
|
||||||
export const CUSTOMER_TRANSACTIONS_VIEWED = 'Customer transactions viewed';
|
|
||||||
export const VENDOR_TRANSACTIONS_VIEWED = 'Vendor transactions viewed';
|
|
||||||
export const SALES_BY_ITEM_VIEWED = 'Sales by item viewed';
|
|
||||||
export const PURCHASES_BY_ITEM_VIEWED = 'Purchases by item viewed';
|
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ export const ACCOUNT_TYPES = [
|
|||||||
normal: ACCOUNT_NORMAL.CREDIT,
|
normal: ACCOUNT_NORMAL.CREDIT,
|
||||||
rootType: ACCOUNT_ROOT_TYPE.LIABILITY,
|
rootType: ACCOUNT_ROOT_TYPE.LIABILITY,
|
||||||
parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY,
|
parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY,
|
||||||
multiCurrency: true,
|
|
||||||
balanceSheet: true,
|
balanceSheet: true,
|
||||||
incomeSheet: false,
|
incomeSheet: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.table('payment_receives', (table) => {
|
|
||||||
table.string('stripe_pintent_id').nullable();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.table('payment_receives', (table) => {
|
|
||||||
table.dropColumn('stripe_pintent_id');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.createTable('pdf_templates', (table) => {
|
|
||||||
table.increments('id').primary();
|
|
||||||
table.text('resource');
|
|
||||||
table.text('template_name');
|
|
||||||
table.json('attributes');
|
|
||||||
table.boolean('predefined').defaultTo(false);
|
|
||||||
table.boolean('default').defaultTo(false);
|
|
||||||
table.timestamps();
|
|
||||||
})
|
|
||||||
.table('sales_invoices', (table) => {
|
|
||||||
table
|
|
||||||
.integer('pdf_template_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('pdf_templates');
|
|
||||||
})
|
|
||||||
.table('sales_estimates', (table) => {
|
|
||||||
table
|
|
||||||
.integer('pdf_template_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('pdf_templates');
|
|
||||||
})
|
|
||||||
.table('sales_receipts', (table) => {
|
|
||||||
table
|
|
||||||
.integer('pdf_template_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('pdf_templates');
|
|
||||||
})
|
|
||||||
.table('credit_notes', (table) => {
|
|
||||||
table
|
|
||||||
.integer('pdf_template_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('pdf_templates');
|
|
||||||
})
|
|
||||||
.table('payment_receives', (table) => {
|
|
||||||
table
|
|
||||||
.integer('pdf_template_id')
|
|
||||||
.unsigned()
|
|
||||||
.references('id')
|
|
||||||
.inTable('pdf_templates');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.table('payment_receives', (table) => {
|
|
||||||
table.dropColumn('pdf_template_id');
|
|
||||||
})
|
|
||||||
.table('credit_notes', (table) => {
|
|
||||||
table.dropColumn('pdf_template_id');
|
|
||||||
})
|
|
||||||
.table('sales_receipts', (table) => {
|
|
||||||
table.dropColumn('pdf_template_id');
|
|
||||||
})
|
|
||||||
.table('sales_estimates', (table) => {
|
|
||||||
table.dropColumn('pdf_template_id');
|
|
||||||
})
|
|
||||||
.table('sales_invoices', (table) => {
|
|
||||||
table.dropColumn('pdf_template_id');
|
|
||||||
})
|
|
||||||
.dropTableIfExists('pdf_templates');
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.createTable('payment_integrations', (table) => {
|
|
||||||
table.increments('id');
|
|
||||||
table.string('service');
|
|
||||||
table.string('name');
|
|
||||||
table.string('slug');
|
|
||||||
table.boolean('payment_enabled').defaultTo(false);
|
|
||||||
table.boolean('payout_enabled').defaultTo(false);
|
|
||||||
table.string('account_id');
|
|
||||||
table.json('options');
|
|
||||||
table.timestamps();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.dropTableIfExists('payment_integrations');
|
|
||||||
};
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.createTable('transactions_payment_methods', (table) => {
|
|
||||||
table.increments('id');
|
|
||||||
table.integer('reference_id').unsigned();
|
|
||||||
table.string('reference_type');
|
|
||||||
table
|
|
||||||
.integer('payment_integration_id')
|
|
||||||
.unsigned()
|
|
||||||
.index()
|
|
||||||
.references('id')
|
|
||||||
.inTable('payment_integrations');
|
|
||||||
table.boolean('enable').defaultTo(false);
|
|
||||||
table.json('options').nullable();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.dropTableIfExists('transactions_payment_methods');
|
|
||||||
};
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex('pdf_templates').insert([
|
|
||||||
{
|
|
||||||
resource: 'SaleInvoice',
|
|
||||||
templateName: 'Standard Template',
|
|
||||||
predefined: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
resource: 'SaleEstimate',
|
|
||||||
templateName: 'Standard Template',
|
|
||||||
predefined: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
resource: 'SaleReceipt',
|
|
||||||
templateName: 'Standard Template',
|
|
||||||
predefined: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
resource: 'CreditNote',
|
|
||||||
templateName: 'Standard Template',
|
|
||||||
predefined: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
resource: 'PaymentReceive',
|
|
||||||
templateName: 'Standard Template',
|
|
||||||
predefined: true,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {};
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.table('items_entries', (table) => {
|
|
||||||
table.decimal('quantity', 13, 3).alter();
|
|
||||||
})
|
|
||||||
.table('inventory_transactions', (table) => {
|
|
||||||
table.decimal('quantity', 13, 3).alter();
|
|
||||||
})
|
|
||||||
.table('inventory_cost_lot_tracker', (table) => {
|
|
||||||
table.decimal('quantity', 13, 3).alter();
|
|
||||||
})
|
|
||||||
.table('items', (table) => {
|
|
||||||
table.decimal('quantityOnHand', 13, 3).alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema
|
|
||||||
.table('items_entries', (table) => {
|
|
||||||
table.integer('quantity').alter();
|
|
||||||
})
|
|
||||||
.table('inventory_transactions', (table) => {
|
|
||||||
table.integer('quantity').alter();
|
|
||||||
})
|
|
||||||
.table('inventory_cost_lot_tracker', (table) => {
|
|
||||||
table.integer('quantity').alter();
|
|
||||||
})
|
|
||||||
.table('items', (table) => {
|
|
||||||
table.integer('quantityOnHand').alter();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.alterTable('sales_invoices', (table) => {
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('credited_amount');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.alterTable('sale_invoices', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('sales_estimates', (table) => {
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('amount');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('sales_estimates', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('sales_receipts', (table) => {
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('amount');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('sales_receipts', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('bills', (table) => {
|
|
||||||
// Discount.
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('amount');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
|
|
||||||
// Adjustment.
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('bills', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('credit_notes', (table) => {
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('exchange_rate');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('credit_notes', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function(knex) {
|
|
||||||
return knex.schema.alterTable('vendor_credits', (table) => {
|
|
||||||
table.decimal('discount', 10, 2).nullable().after('amount');
|
|
||||||
table.string('discount_type').nullable().after('discount');
|
|
||||||
table.decimal('adjustment', 10, 2).nullable().after('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function(knex) {
|
|
||||||
return knex.schema.alterTable('vendor_credits', (table) => {
|
|
||||||
table.dropColumn('discount');
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
table.dropColumn('adjustment');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.up = function (knex) {
|
|
||||||
return knex.schema.alterTable('items_entries', (table) => {
|
|
||||||
table.string('discount_type').defaultTo('percentage').after('discount');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { import("knex").Knex } knex
|
|
||||||
* @returns { Promise<void> }
|
|
||||||
*/
|
|
||||||
exports.down = function (knex) {
|
|
||||||
return knex.schema.alterTable('items_entries', (table) => {
|
|
||||||
table.dropColumn('discount_type');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,14 +1,3 @@
|
|||||||
export const OtherExpensesAccount = {
|
|
||||||
name: 'Other Expenses',
|
|
||||||
slug: 'other-expenses',
|
|
||||||
account_type: 'other-expense',
|
|
||||||
code: '40011',
|
|
||||||
description: '',
|
|
||||||
active: 1,
|
|
||||||
index: 1,
|
|
||||||
predefined: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TaxPayableAccount = {
|
export const TaxPayableAccount = {
|
||||||
name: 'Tax Payable',
|
name: 'Tax Payable',
|
||||||
slug: 'tax-payable',
|
slug: 'tax-payable',
|
||||||
@@ -42,47 +31,6 @@ export const PrepardExpenses = {
|
|||||||
predefined: true,
|
predefined: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StripeClearingAccount = {
|
|
||||||
name: 'Stripe Clearing',
|
|
||||||
slug: 'stripe-clearing',
|
|
||||||
account_type: 'other-current-asset',
|
|
||||||
parent_account_id: null,
|
|
||||||
code: '100020',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DiscountExpenseAccount = {
|
|
||||||
name: 'Discount',
|
|
||||||
slug: 'discount',
|
|
||||||
account_type: 'other-income',
|
|
||||||
code: '40008',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PurchaseDiscountAccount = {
|
|
||||||
name: 'Purchase Discount',
|
|
||||||
slug: 'purchase-discount',
|
|
||||||
account_type: 'other-expense',
|
|
||||||
code: '40009',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const OtherChargesAccount = {
|
|
||||||
name: 'Other Charges',
|
|
||||||
slug: 'other-charges',
|
|
||||||
account_type: 'other-income',
|
|
||||||
code: '40010',
|
|
||||||
active: true,
|
|
||||||
index: 1,
|
|
||||||
predefined: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: 'Bank Account',
|
name: 'Bank Account',
|
||||||
@@ -272,7 +220,17 @@ export default [
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Expenses
|
// Expenses
|
||||||
OtherExpensesAccount,
|
{
|
||||||
|
name: 'Other Expenses',
|
||||||
|
slug: 'other-expenses',
|
||||||
|
account_type: 'other-expense',
|
||||||
|
parent_account_id: null,
|
||||||
|
code: '40001',
|
||||||
|
description: '',
|
||||||
|
active: 1,
|
||||||
|
index: 1,
|
||||||
|
predefined: 1,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Cost of Goods Sold',
|
name: 'Cost of Goods Sold',
|
||||||
slug: 'cost-of-goods-sold',
|
slug: 'cost-of-goods-sold',
|
||||||
@@ -389,7 +347,4 @@ export default [
|
|||||||
},
|
},
|
||||||
UnearnedRevenueAccount,
|
UnearnedRevenueAccount,
|
||||||
PrepardExpenses,
|
PrepardExpenses,
|
||||||
DiscountExpenseAccount,
|
|
||||||
PurchaseDiscountAccount,
|
|
||||||
OtherChargesAccount,
|
|
||||||
];
|
];
|
||||||
|
|||||||
63
packages/server/src/decorators/swagger-decorators.ts
Normal file
63
packages/server/src/decorators/swagger-decorators.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
export const swaggerDocs = {
|
||||||
|
tags: {},
|
||||||
|
paths: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decorator to set a tag for a route
|
||||||
|
export function ApiTags(tag) {
|
||||||
|
return function (target) {
|
||||||
|
if (!swaggerDocs.tags[tag]) {
|
||||||
|
swaggerDocs.tags[tag] = { name: tag };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to add an operation for a specific route
|
||||||
|
export function ApiOperation(options) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
const routePath = Reflect.getMetadata('path', target, propertyKey);
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath] = swaggerDocs.paths[routePath] || {};
|
||||||
|
swaggerDocs.paths[routePath].get = {
|
||||||
|
summary: options.summary,
|
||||||
|
description: options.description || '',
|
||||||
|
responses: options.responses || {
|
||||||
|
200: {
|
||||||
|
description: 'Successful Response',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to define the route path
|
||||||
|
export function Route(path) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
Reflect.defineMetadata('path', path, target, propertyKey);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorator to add a response schema for a specific route
|
||||||
|
export function ApiResponse(options) {
|
||||||
|
return function (target, propertyKey, descriptor) {
|
||||||
|
const routePath = Reflect.getMetadata('path', target, propertyKey);
|
||||||
|
|
||||||
|
if (!swaggerDocs.paths[routePath]) {
|
||||||
|
swaggerDocs.paths[routePath] = { get: {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath].get.responses =
|
||||||
|
swaggerDocs.paths[routePath].get.responses || {};
|
||||||
|
|
||||||
|
swaggerDocs.paths[routePath].get.responses[options.status] = {
|
||||||
|
description: options.description || 'No description provided',
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: options.schema || {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ import { IDynamicListFilterDTO } from './DynamicFilter';
|
|||||||
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
import { IBillLandedCost } from './LandedCost';
|
import { IBillLandedCost } from './LandedCost';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
import { DiscountType } from './SaleInvoice';
|
|
||||||
|
|
||||||
export interface IBillDTO {
|
export interface IBillDTO {
|
||||||
vendorId: number;
|
vendorId: number;
|
||||||
@@ -23,13 +22,6 @@ export interface IBillDTO {
|
|||||||
projectId?: number;
|
projectId?: number;
|
||||||
isInclusiveTax?: boolean;
|
isInclusiveTax?: boolean;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
// # Discount
|
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBillEditDTO {
|
export interface IBillEditDTO {
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ export interface ICashflowTransactionUncategorizedPayload {
|
|||||||
tenantId: number;
|
tenantId: number;
|
||||||
uncategorizedTransactionId: number;
|
uncategorizedTransactionId: number;
|
||||||
uncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
uncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
||||||
oldMainUncategorizedTransaction: IUncategorizedCashflowTransaction;
|
|
||||||
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
oldUncategorizedTransactions: Array<IUncategorizedCashflowTransaction>;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { DiscountType, IDynamicListFilter, IItemEntry } from '@/interfaces';
|
import { IDynamicListFilter, IItemEntry } from '@/interfaces';
|
||||||
import { ILedgerEntry } from './Ledger';
|
import { ILedgerEntry } from './Ledger';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
@@ -23,9 +23,6 @@ export interface ICreditNoteNewDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreditNoteEditDTO {
|
export interface ICreditNoteEditDTO {
|
||||||
@@ -65,8 +62,6 @@ export interface ICreditNote {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId: number;
|
warehouseId: number;
|
||||||
createdAt?: Date;
|
createdAt?: Date;
|
||||||
termsConditions: string;
|
|
||||||
note: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CreditNoteAction {
|
export enum CreditNoteAction {
|
||||||
@@ -263,61 +258,3 @@ export type ICreditNoteGLCommonEntry = Pick<
|
|||||||
| 'debit'
|
| 'debit'
|
||||||
| 'branchId'
|
| 'branchId'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface CreditNotePdfTemplateAttributes {
|
|
||||||
// # Primary color
|
|
||||||
primaryColor: string;
|
|
||||||
secondaryColor: string;
|
|
||||||
|
|
||||||
// # Company logo
|
|
||||||
showCompanyLogo: boolean;
|
|
||||||
companyLogo: string;
|
|
||||||
|
|
||||||
// # Company name
|
|
||||||
companyName: string;
|
|
||||||
|
|
||||||
// # Customer Address
|
|
||||||
showCustomerAddress: boolean;
|
|
||||||
customerAddress: string;
|
|
||||||
|
|
||||||
// # Company address
|
|
||||||
showCompanyAddress: boolean;
|
|
||||||
companyAddress: string;
|
|
||||||
billedToLabel: string;
|
|
||||||
|
|
||||||
total: string;
|
|
||||||
totalLabel: string;
|
|
||||||
showTotal: boolean;
|
|
||||||
|
|
||||||
subtotal: string;
|
|
||||||
subtotalLabel: string;
|
|
||||||
showSubtotal: boolean;
|
|
||||||
|
|
||||||
showCustomerNote: boolean;
|
|
||||||
customerNote: string;
|
|
||||||
customerNoteLabel: string;
|
|
||||||
|
|
||||||
showTermsConditions: boolean;
|
|
||||||
termsConditions: string;
|
|
||||||
termsConditionsLabel: string;
|
|
||||||
|
|
||||||
lines: Array<{
|
|
||||||
item: string;
|
|
||||||
description: string;
|
|
||||||
rate: string;
|
|
||||||
quantity: string;
|
|
||||||
total: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
showCreditNoteNumber: boolean;
|
|
||||||
creditNoteNumberLabel: string;
|
|
||||||
creditNoteNumebr: string;
|
|
||||||
|
|
||||||
creditNoteDate: string;
|
|
||||||
showCreditNoteDate: boolean;
|
|
||||||
creditNoteDateLabel: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICreditNoteState {
|
|
||||||
defaultTemplateId: number;
|
|
||||||
}
|
|
||||||
@@ -4,5 +4,4 @@ export const ACCEPT_TYPE = {
|
|||||||
APPLICATION_JSON_TABLE: 'application/json+table',
|
APPLICATION_JSON_TABLE: 'application/json+table',
|
||||||
APPLICATION_XLSX: 'application/xlsx',
|
APPLICATION_XLSX: 'application/xlsx',
|
||||||
APPLICATION_CSV: 'application/csv',
|
APPLICATION_CSV: 'application/csv',
|
||||||
APPLICATION_TEXT_HTML: 'application/json+html',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,17 +13,14 @@ export interface IItemEntry {
|
|||||||
|
|
||||||
itemId: number;
|
itemId: number;
|
||||||
description: string;
|
description: string;
|
||||||
discountType?: string;
|
|
||||||
discount: number;
|
discount: number;
|
||||||
quantity: number;
|
quantity: number;
|
||||||
rate: number;
|
rate: number;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
|
||||||
total: number;
|
total: number;
|
||||||
totalExcludingTax?: number;
|
amountInclusingTax: number;
|
||||||
|
amountExludingTax: number;
|
||||||
subtotalInclusingTax: number;
|
|
||||||
subtotalExcludingTax: number;
|
|
||||||
discountAmount: number;
|
discountAmount: number;
|
||||||
|
|
||||||
landedCost: number;
|
landedCost: number;
|
||||||
|
|||||||
@@ -30,15 +30,18 @@ export interface AddressItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonMailOptions {
|
export interface CommonMailOptions {
|
||||||
from: Array<string>;
|
toAddresses: AddressItem[];
|
||||||
|
fromAddresses: AddressItem[];
|
||||||
|
from: string;
|
||||||
|
to: string | string[];
|
||||||
subject: string;
|
subject: string;
|
||||||
message: string;
|
body: string;
|
||||||
to: Array<string>;
|
data?: Record<string, any>;
|
||||||
cc?: Array<string>;
|
|
||||||
bcc?: Array<string>;
|
|
||||||
formatArgs?: Record<string, any>;
|
|
||||||
toOptions: Array<AddressItem>;
|
|
||||||
fromOptions: Array<AddressItem>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {}
|
export interface CommonMailOptionsDTO {
|
||||||
|
to?: string | string[];
|
||||||
|
from?: string;
|
||||||
|
subject?: string;
|
||||||
|
body?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export interface IPaymentReceived {
|
|||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
pdfTemplateId?: number;
|
|
||||||
}
|
}
|
||||||
export interface IPaymentReceivedCreateDTO {
|
export interface IPaymentReceivedCreateDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
@@ -177,9 +176,7 @@ export type IPaymentReceiveGLCommonEntry = Pick<
|
|||||||
| 'branchId'
|
| 'branchId'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface PaymentReceiveMailOpts extends CommonMailOptions {
|
export interface PaymentReceiveMailOpts extends CommonMailOptions {}
|
||||||
attachPdf?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentReceiveMailOptsDTO extends CommonMailOptionsDTO {}
|
export interface PaymentReceiveMailOptsDTO extends CommonMailOptionsDTO {}
|
||||||
|
|
||||||
@@ -188,59 +185,3 @@ export interface PaymentReceiveMailPresendEvent {
|
|||||||
paymentReceiveId: number;
|
paymentReceiveId: number;
|
||||||
messageOptions: PaymentReceiveMailOptsDTO;
|
messageOptions: PaymentReceiveMailOptsDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaymentReceivedPdfLineItem {
|
|
||||||
item: string;
|
|
||||||
description: string;
|
|
||||||
rate: string;
|
|
||||||
quantity: string;
|
|
||||||
total: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentReceivedPdfTax {
|
|
||||||
label: string;
|
|
||||||
amount: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentReceivedPdfTemplateAttributes {
|
|
||||||
primaryColor: string;
|
|
||||||
secondaryColor: string;
|
|
||||||
showCompanyLogo: boolean;
|
|
||||||
companyLogo: string;
|
|
||||||
companyName: string;
|
|
||||||
|
|
||||||
// Customer Address
|
|
||||||
showCustomerAddress: boolean;
|
|
||||||
customerAddress: string;
|
|
||||||
|
|
||||||
// Company address
|
|
||||||
showCompanyAddress: boolean;
|
|
||||||
companyAddress: string;
|
|
||||||
billedToLabel: string;
|
|
||||||
|
|
||||||
total: string;
|
|
||||||
totalLabel: string;
|
|
||||||
showTotal: boolean;
|
|
||||||
|
|
||||||
subtotal: string;
|
|
||||||
subtotalLabel: string;
|
|
||||||
showSubtotal: boolean;
|
|
||||||
|
|
||||||
lines: Array<{
|
|
||||||
invoiceNumber: string;
|
|
||||||
invoiceAmount: string;
|
|
||||||
paidAmount: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
showPaymentReceivedNumber: boolean;
|
|
||||||
paymentReceivedNumberLabel: string;
|
|
||||||
paymentReceivedNumebr: string;
|
|
||||||
|
|
||||||
paymentReceivedDate: string;
|
|
||||||
showPaymentReceivedDate: boolean;
|
|
||||||
paymentReceivedDateLabel: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPaymentReceivedState {
|
|
||||||
defaultTemplateId: number;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
|||||||
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
import { IDynamicListFilterDTO } from '@/interfaces/DynamicFilter';
|
||||||
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
import { DiscountType } from './SaleInvoice';
|
|
||||||
|
|
||||||
export interface ISaleEstimate {
|
export interface ISaleEstimate {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -25,14 +24,6 @@ export interface ISaleEstimate {
|
|||||||
|
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
|
|
||||||
total?: number;
|
|
||||||
totalLocal?: number;
|
|
||||||
|
|
||||||
discountAmount?: number;
|
|
||||||
discountPercentage?: number | null;
|
|
||||||
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
export interface ISaleEstimateDTO {
|
export interface ISaleEstimateDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
@@ -49,13 +40,6 @@ export interface ISaleEstimateDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
// # Discount
|
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
|
|
||||||
// # Adjustment
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
export interface ISalesEstimatesFilter extends IDynamicListFilterDTO {
|
||||||
@@ -159,7 +143,3 @@ export interface ISaleEstimateMailPresendEvent {
|
|||||||
saleEstimateId: number;
|
saleEstimateId: number;
|
||||||
messageOptions: SaleEstimateMailOptionsDTO;
|
messageOptions: SaleEstimateMailOptionsDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleEstimateState {
|
|
||||||
defaultTemplateId: number;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,34 +5,6 @@ import { IDynamicListFilter } from '@/interfaces/DynamicFilter';
|
|||||||
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
import { IItemEntry, IItemEntryDTO } from './ItemEntry';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
export interface PaymentIntegrationTransactionLink {
|
|
||||||
id: number;
|
|
||||||
enable: true;
|
|
||||||
paymentIntegrationId: number;
|
|
||||||
referenceType: string;
|
|
||||||
referenceId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentIntegrationTransactionLinkEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
enable: true;
|
|
||||||
paymentIntegrationId: number;
|
|
||||||
referenceType: string;
|
|
||||||
referenceId: number;
|
|
||||||
saleInvoiceId: number;
|
|
||||||
trx?: Knex.Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaymentIntegrationTransactionLinkDeleteEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
enable: true;
|
|
||||||
paymentIntegrationId: number;
|
|
||||||
referenceType: string;
|
|
||||||
referenceId: number;
|
|
||||||
oldSaleInvoiceId: number;
|
|
||||||
trx?: Knex.Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISaleInvoice {
|
export interface ISaleInvoice {
|
||||||
id: number;
|
id: number;
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -73,25 +45,6 @@ export interface ISaleInvoice {
|
|||||||
subtotal: number;
|
subtotal: number;
|
||||||
subtotalLocal: number;
|
subtotalLocal: number;
|
||||||
subtotalExludingTax: number;
|
subtotalExludingTax: number;
|
||||||
|
|
||||||
termsConditions: string;
|
|
||||||
invoiceMessage: string;
|
|
||||||
|
|
||||||
pdfTemplateId?: number;
|
|
||||||
|
|
||||||
paymentMethods?: Array<PaymentIntegrationTransactionLink>;
|
|
||||||
|
|
||||||
adjustment?: number;
|
|
||||||
adjustmentLocal?: number | null;
|
|
||||||
|
|
||||||
discount?: number;
|
|
||||||
discountAmount?: number;
|
|
||||||
discountAmountLocal?: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum DiscountType {
|
|
||||||
Percentage = 'percentage',
|
|
||||||
Amount = 'amount',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleInvoiceDTO {
|
export interface ISaleInvoiceDTO {
|
||||||
@@ -114,13 +67,6 @@ export interface ISaleInvoiceDTO {
|
|||||||
isInclusiveTax?: boolean;
|
isInclusiveTax?: boolean;
|
||||||
|
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
// # Discount
|
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
|
|
||||||
// # Adjustments
|
|
||||||
adjustments?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleInvoiceCreateDTO extends ISaleInvoiceDTO {
|
export interface ISaleInvoiceCreateDTO extends ISaleInvoiceDTO {
|
||||||
@@ -185,13 +131,7 @@ export interface ISaleInvoiceEditingPayload {
|
|||||||
|
|
||||||
export interface ISaleInvoiceDeletePayload {
|
export interface ISaleInvoiceDeletePayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
oldSaleInvoice: ISaleInvoice;
|
saleInvoice: ISaleInvoice;
|
||||||
saleInvoiceId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISaleInvoiceDeletingPayload {
|
|
||||||
tenantId: number;
|
|
||||||
oldSaleInvoice: ISaleInvoice;
|
|
||||||
saleInvoiceId: number;
|
saleInvoiceId: number;
|
||||||
trx: Knex.Transaction;
|
trx: Knex.Transaction;
|
||||||
}
|
}
|
||||||
@@ -253,32 +193,7 @@ export enum SaleInvoiceAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SaleInvoiceMailOptions extends CommonMailOptions {
|
export interface SaleInvoiceMailOptions extends CommonMailOptions {
|
||||||
attachInvoice?: boolean;
|
attachInvoice: boolean;
|
||||||
formatArgs?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SaleInvoiceMailState extends SaleInvoiceMailOptions {
|
|
||||||
invoiceNo: string;
|
|
||||||
|
|
||||||
invoiceDate: string;
|
|
||||||
invoiceDateFormatted: string;
|
|
||||||
|
|
||||||
dueDate: string;
|
|
||||||
dueDateFormatted: string;
|
|
||||||
|
|
||||||
total: number;
|
|
||||||
totalFormatted: string;
|
|
||||||
|
|
||||||
subtotal: number;
|
|
||||||
subtotalFormatted: number;
|
|
||||||
|
|
||||||
companyName: string;
|
|
||||||
companyLogoUri: string;
|
|
||||||
|
|
||||||
customerName: string;
|
|
||||||
|
|
||||||
// # Invoice entries
|
|
||||||
entries?: Array<{ label: string; total: string; quantity: string | number }>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendInvoiceMailDTO extends CommonMailOptionsDTO {
|
export interface SendInvoiceMailDTO extends CommonMailOptionsDTO {
|
||||||
@@ -295,7 +210,6 @@ export interface ISaleInvoiceMailSend {
|
|||||||
tenantId: number;
|
tenantId: number;
|
||||||
saleInvoiceId: number;
|
saleInvoiceId: number;
|
||||||
messageOptions: SendInvoiceMailDTO;
|
messageOptions: SendInvoiceMailDTO;
|
||||||
formattedMessageOptions: SaleInvoiceMailOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleInvoiceMailSent {
|
export interface ISaleInvoiceMailSent {
|
||||||
@@ -303,89 +217,3 @@ export interface ISaleInvoiceMailSent {
|
|||||||
saleInvoiceId: number;
|
saleInvoiceId: number;
|
||||||
messageOptions: SendInvoiceMailDTO;
|
messageOptions: SendInvoiceMailDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoice Pdf Document
|
|
||||||
export interface InvoicePdfLine {
|
|
||||||
item: string;
|
|
||||||
description: string;
|
|
||||||
rate: string;
|
|
||||||
quantity: string;
|
|
||||||
total: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InvoicePdfTax {
|
|
||||||
label: string;
|
|
||||||
amount: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InvoicePdfTemplateAttributes {
|
|
||||||
primaryColor: string;
|
|
||||||
secondaryColor: string;
|
|
||||||
|
|
||||||
companyName: string;
|
|
||||||
|
|
||||||
showCompanyLogo: boolean;
|
|
||||||
companyLogo: string;
|
|
||||||
|
|
||||||
dueDate: string;
|
|
||||||
dueDateLabel: string;
|
|
||||||
showDueDate: boolean;
|
|
||||||
|
|
||||||
dateIssue: string;
|
|
||||||
dateIssueLabel: string;
|
|
||||||
showDateIssue: boolean;
|
|
||||||
|
|
||||||
invoiceNumberLabel: string;
|
|
||||||
invoiceNumber: string;
|
|
||||||
showInvoiceNumber: boolean;
|
|
||||||
|
|
||||||
// Customer Address
|
|
||||||
showCustomerAddress: boolean;
|
|
||||||
customerAddress: string;
|
|
||||||
|
|
||||||
// Company address
|
|
||||||
showCompanyAddress: boolean;
|
|
||||||
companyAddress: string;
|
|
||||||
billedToLabel: string;
|
|
||||||
|
|
||||||
lineItemLabel: string;
|
|
||||||
lineDescriptionLabel: string;
|
|
||||||
lineRateLabel: string;
|
|
||||||
lineTotalLabel: string;
|
|
||||||
|
|
||||||
totalLabel: string;
|
|
||||||
subtotalLabel: string;
|
|
||||||
discountLabel: string;
|
|
||||||
paymentMadeLabel: string;
|
|
||||||
|
|
||||||
showTotal: boolean;
|
|
||||||
showSubtotal: boolean;
|
|
||||||
showDiscount: boolean;
|
|
||||||
showTaxes: boolean;
|
|
||||||
showPaymentMade: boolean;
|
|
||||||
|
|
||||||
total: string;
|
|
||||||
subtotal: string;
|
|
||||||
discount: string;
|
|
||||||
paymentMade: string;
|
|
||||||
|
|
||||||
// Due Amount
|
|
||||||
dueAmount: string;
|
|
||||||
showDueAmount: boolean;
|
|
||||||
dueAmountLabel: string;
|
|
||||||
|
|
||||||
termsConditionsLabel: string;
|
|
||||||
showTermsConditions: boolean;
|
|
||||||
termsConditions: string;
|
|
||||||
|
|
||||||
lines: InvoicePdfLine[];
|
|
||||||
taxes: InvoicePdfTax[];
|
|
||||||
|
|
||||||
statementLabel: string;
|
|
||||||
showStatement: boolean;
|
|
||||||
statement: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISaleInvocieState {
|
|
||||||
defaultTemplateId: number;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Knex } from 'knex';
|
|||||||
import { IItemEntry } from './ItemEntry';
|
import { IItemEntry } from './ItemEntry';
|
||||||
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
import { CommonMailOptions, CommonMailOptionsDTO } from './Mailable';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
import { DiscountType } from './SaleInvoice';
|
|
||||||
|
|
||||||
export interface ISaleReceipt {
|
export interface ISaleReceipt {
|
||||||
id?: number;
|
id?: number;
|
||||||
@@ -28,20 +27,6 @@ export interface ISaleReceipt {
|
|||||||
|
|
||||||
localAmount?: number;
|
localAmount?: number;
|
||||||
entries?: IItemEntry[];
|
entries?: IItemEntry[];
|
||||||
|
|
||||||
subtotal?: number;
|
|
||||||
subtotalLocal?: number;
|
|
||||||
|
|
||||||
total?: number;
|
|
||||||
totalLocal?: number;
|
|
||||||
|
|
||||||
discountAmount: number;
|
|
||||||
discountPercentage?: number | null;
|
|
||||||
|
|
||||||
adjustment?: number;
|
|
||||||
adjustmentLocal?: number | null;
|
|
||||||
|
|
||||||
discountAmountLocal?: number | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesReceiptsFilter {
|
export interface ISalesReceiptsFilter {
|
||||||
@@ -62,11 +47,6 @@ export interface ISaleReceiptDTO {
|
|||||||
entries: any[];
|
entries: any[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISalesReceiptsService {
|
export interface ISalesReceiptsService {
|
||||||
@@ -175,64 +155,3 @@ export interface ISaleReceiptMailPresend {
|
|||||||
saleReceiptId: number;
|
saleReceiptId: number;
|
||||||
messageOptions: SaleReceiptMailOptsDTO;
|
messageOptions: SaleReceiptMailOptsDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaleReceiptBrandingTemplateAttributes {
|
|
||||||
primaryColor: string;
|
|
||||||
secondaryColor: string;
|
|
||||||
showCompanyLogo: boolean;
|
|
||||||
companyLogo: string;
|
|
||||||
companyName: string;
|
|
||||||
|
|
||||||
// Customer Address
|
|
||||||
showCustomerAddress: boolean;
|
|
||||||
customerAddress: string;
|
|
||||||
|
|
||||||
// Company address
|
|
||||||
showCompanyAddress: boolean;
|
|
||||||
companyAddress: string;
|
|
||||||
billedToLabel: string;
|
|
||||||
|
|
||||||
// Total
|
|
||||||
total: string;
|
|
||||||
totalLabel: string;
|
|
||||||
showTotal: boolean;
|
|
||||||
|
|
||||||
// Subtotal
|
|
||||||
subtotal: string;
|
|
||||||
subtotalLabel: string;
|
|
||||||
showSubtotal: boolean;
|
|
||||||
|
|
||||||
// Customer Note
|
|
||||||
showCustomerNote: boolean;
|
|
||||||
customerNote: string;
|
|
||||||
customerNoteLabel: string;
|
|
||||||
|
|
||||||
// Terms & Conditions
|
|
||||||
showTermsConditions: boolean;
|
|
||||||
termsConditions: string;
|
|
||||||
termsConditionsLabel: string;
|
|
||||||
|
|
||||||
// Lines
|
|
||||||
lines: Array<{
|
|
||||||
item: string;
|
|
||||||
description: string;
|
|
||||||
rate: string;
|
|
||||||
quantity: string;
|
|
||||||
total: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
// Receipt Number
|
|
||||||
showReceiptNumber: boolean;
|
|
||||||
receiptNumberLabel: string;
|
|
||||||
receiptNumebr: string;
|
|
||||||
|
|
||||||
// Receipt Date
|
|
||||||
receiptDate: string;
|
|
||||||
showReceiptDate: boolean;
|
|
||||||
receiptDateLabel: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface ISaleReceiptState {
|
|
||||||
defaultTemplateId: number;
|
|
||||||
}
|
|
||||||
@@ -18,26 +18,14 @@ export interface IOrganizationBuildDTO {
|
|||||||
dateFormat?: string;
|
dateFormat?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OrganizationAddressDTO {
|
|
||||||
address1: string;
|
|
||||||
address2: string;
|
|
||||||
postalCode: string;
|
|
||||||
city: string;
|
|
||||||
stateProvince: string;
|
|
||||||
phone: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IOrganizationUpdateDTO {
|
export interface IOrganizationUpdateDTO {
|
||||||
name: string;
|
name: string;
|
||||||
location?: string;
|
location: string;
|
||||||
baseCurrency?: string;
|
baseCurrency: string;
|
||||||
timezone?: string;
|
timezone: string;
|
||||||
fiscalYear?: string;
|
fiscalYear: string;
|
||||||
industry?: string;
|
industry: string;
|
||||||
taxNumber?: string;
|
taxNumber: string;
|
||||||
primaryColor?: string;
|
|
||||||
logoKey?: string;
|
|
||||||
address?: OrganizationAddressDTO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrganizationBuildEventPayload {
|
export interface IOrganizationBuildEventPayload {
|
||||||
@@ -48,4 +36,4 @@ export interface IOrganizationBuildEventPayload {
|
|||||||
|
|
||||||
export interface IOrganizationBuiltEventPayload {
|
export interface IOrganizationBuiltEventPayload {
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
export interface StripePaymentLinkCreatedEventPayload {
|
|
||||||
tenantId: number;
|
|
||||||
paymentLinkId: string;
|
|
||||||
saleInvoiceId: number;
|
|
||||||
stripeIntegrationId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StripeCheckoutSessionCompletedEventPayload {
|
|
||||||
event: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StripeInvoiceCheckoutSessionPOJO {
|
|
||||||
sessionId: string;
|
|
||||||
publishableKey: string;
|
|
||||||
redirectTo: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StripeWebhookEventPayload {
|
|
||||||
event: any;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DiscountType, IDynamicListFilter, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
import { IDynamicListFilter, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { AttachmentLinkDTO } from './Attachments';
|
import { AttachmentLinkDTO } from './Attachments';
|
||||||
|
|
||||||
@@ -63,11 +63,6 @@ export interface IVendorCreditDTO {
|
|||||||
branchId?: number;
|
branchId?: number;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|
||||||
discount?: number;
|
|
||||||
discountType?: DiscountType;
|
|
||||||
|
|
||||||
adjustment?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
|
export interface IVendorCreditCreateDTO extends IVendorCreditDTO {}
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ export default class Mail {
|
|||||||
subject: string = '';
|
subject: string = '';
|
||||||
content: string = '';
|
content: string = '';
|
||||||
to: string | string[];
|
to: string | string[];
|
||||||
cc: string | string[];
|
|
||||||
bcc: string | string[];
|
|
||||||
replyTo: string | string[];
|
|
||||||
from: string = `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`;
|
from: string = `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`;
|
||||||
data: { [key: string]: string | number };
|
data: { [key: string]: string | number };
|
||||||
attachments: IMailAttachment[];
|
attachments: IMailAttachment[];
|
||||||
@@ -23,12 +20,9 @@ export default class Mail {
|
|||||||
return {
|
return {
|
||||||
to: this.to,
|
to: this.to,
|
||||||
from: this.from,
|
from: this.from,
|
||||||
cc: this.cc,
|
|
||||||
bcc: this.bcc,
|
|
||||||
subject: this.subject,
|
subject: this.subject,
|
||||||
html: this.html,
|
html: this.html,
|
||||||
attachments: this.attachments,
|
attachments: this.attachments,
|
||||||
replyTo: this.replyTo,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,21 +60,6 @@ export default class Mail {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCC(cc: string | string[]) {
|
|
||||||
this.cc = cc;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setBCC(bcc: string | string[]) {
|
|
||||||
this.bcc = bcc;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
setReplyTo(replyTo: string | string[]) {
|
|
||||||
this.replyTo = replyTo;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets from address to the mail.
|
* Sets from address to the mail.
|
||||||
* @param {string} from
|
* @param {string} from
|
||||||
@@ -93,7 +72,7 @@ export default class Mail {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set attachments to the mail.
|
* Set attachments to the mail.
|
||||||
* @param {IMailAttachment[]} attachments
|
* @param {IMailAttachment[]} attachments
|
||||||
* @returns {Mail}
|
* @returns {Mail}
|
||||||
*/
|
*/
|
||||||
setAttachments(attachments: IMailAttachment[]) {
|
setAttachments(attachments: IMailAttachment[]) {
|
||||||
|
|||||||
@@ -117,10 +117,8 @@ import { DisconnectPlaidItemOnAccountDeleted } from '@/services/Banking/BankAcco
|
|||||||
import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
|
import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
|
||||||
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
|
||||||
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
|
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
|
||||||
|
import { TriggerInvalidateCacheOnSubscriptionChange } from '@/services/Subscription/events/TriggerInvalidateCacheOnSubscriptionChange';
|
||||||
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
||||||
import { InvoicePaymentIntegrationSubscriber } from '@/services/Sales/Invoices/subscribers/InvoicePaymentIntegrationSubscriber';
|
|
||||||
import { StripeWebhooksSubscriber } from '@/services/StripePayment/events/StripeWebhooksSubscriber';
|
|
||||||
import { SeedStripeAccountsOnOAuthGrantedSubscriber } from '@/services/StripePayment/events/SeedStripeAccounts';
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -254,6 +252,7 @@ export const susbcribers = () => {
|
|||||||
// Subscription
|
// Subscription
|
||||||
SubscribeFreeOnSignupCommunity,
|
SubscribeFreeOnSignupCommunity,
|
||||||
SendVerfiyMailOnSignUp,
|
SendVerfiyMailOnSignUp,
|
||||||
|
TriggerInvalidateCacheOnSubscriptionChange,
|
||||||
|
|
||||||
// Attachments
|
// Attachments
|
||||||
AttachmentsOnSaleInvoiceCreated,
|
AttachmentsOnSaleInvoiceCreated,
|
||||||
@@ -292,11 +291,6 @@ export const susbcribers = () => {
|
|||||||
// Demo Account
|
// Demo Account
|
||||||
SeedInitialDemoAccountDataOnOrgBuild,
|
SeedInitialDemoAccountDataOnOrgBuild,
|
||||||
|
|
||||||
// Stripe Payment
|
|
||||||
InvoicePaymentIntegrationSubscriber,
|
|
||||||
StripeWebhooksSubscriber,
|
|
||||||
SeedStripeAccountsOnOAuthGrantedSubscriber,
|
|
||||||
|
|
||||||
...EventsTrackerListeners
|
...EventsTrackerListeners
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,9 +68,6 @@ import { BankRule } from '@/models/BankRule';
|
|||||||
import { BankRuleCondition } from '@/models/BankRuleCondition';
|
import { BankRuleCondition } from '@/models/BankRuleCondition';
|
||||||
import { RecognizedBankTransaction } from '@/models/RecognizedBankTransaction';
|
import { RecognizedBankTransaction } from '@/models/RecognizedBankTransaction';
|
||||||
import { MatchedBankTransaction } from '@/models/MatchedBankTransaction';
|
import { MatchedBankTransaction } from '@/models/MatchedBankTransaction';
|
||||||
import { PdfTemplate } from '@/models/PdfTemplate';
|
|
||||||
import { PaymentIntegration } from '@/models/PaymentIntegration';
|
|
||||||
import { TransactionPaymentServiceEntry } from '@/models/TransactionPaymentServiceEntry';
|
|
||||||
|
|
||||||
export default (knex) => {
|
export default (knex) => {
|
||||||
const models = {
|
const models = {
|
||||||
@@ -142,9 +139,6 @@ export default (knex) => {
|
|||||||
BankRuleCondition,
|
BankRuleCondition,
|
||||||
RecognizedBankTransaction,
|
RecognizedBankTransaction,
|
||||||
MatchedBankTransaction,
|
MatchedBankTransaction,
|
||||||
PdfTemplate,
|
|
||||||
PaymentIntegration,
|
|
||||||
TransactionPaymentServiceEntry,
|
|
||||||
};
|
};
|
||||||
return mapValues(models, (model) => model.bindKnex(knex));
|
return mapValues(models, (model) => model.bindKnex(knex));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { Model, raw, mixin } from 'objection';
|
import { Model, raw, mixin } from 'objection';
|
||||||
import { castArray, defaultTo, difference } from 'lodash';
|
import { castArray, difference } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import * as R from 'ramda';
|
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import BillSettings from './Bill.Settings';
|
import BillSettings from './Bill.Settings';
|
||||||
import ModelSetting from './ModelSetting';
|
import ModelSetting from './ModelSetting';
|
||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
|
|
||||||
export default class Bill extends mixin(TenantModel, [
|
export default class Bill extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
@@ -23,11 +21,6 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
public taxAmountWithheld: number;
|
public taxAmountWithheld: number;
|
||||||
public exchangeRate: number;
|
public exchangeRate: number;
|
||||||
|
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
|
|
||||||
public adjustment: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timestamps columns.
|
* Timestamps columns.
|
||||||
*/
|
*/
|
||||||
@@ -54,13 +47,6 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
'localAllocatedCostAmount',
|
'localAllocatedCostAmount',
|
||||||
'billableAmount',
|
'billableAmount',
|
||||||
'amountLocal',
|
'amountLocal',
|
||||||
|
|
||||||
'discountAmount',
|
|
||||||
'discountAmountLocal',
|
|
||||||
'discountPercentage',
|
|
||||||
|
|
||||||
'adjustmentLocal',
|
|
||||||
|
|
||||||
'subtotal',
|
'subtotal',
|
||||||
'subtotalLocal',
|
'subtotalLocal',
|
||||||
'subtotalExludingTax',
|
'subtotalExludingTax',
|
||||||
@@ -112,53 +98,14 @@ export default class Bill extends mixin(TenantModel, [
|
|||||||
return this.taxAmountWithheld * this.exchangeRate;
|
return this.taxAmountWithheld * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountAmountLocal() {
|
|
||||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjustment amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get adjustmentLocal() {
|
|
||||||
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice total. (Tax included)
|
* Invoice total. (Tax included)
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
return this.isInclusiveTax
|
||||||
|
? this.subtotal
|
||||||
return R.compose(
|
: this.subtotal + this.taxAmountWithheld;
|
||||||
R.add(adjustmentAmount),
|
|
||||||
R.subtract(R.__, this.discountAmount),
|
|
||||||
R.when(R.always(this.isInclusiveTax), R.add(this.taxAmountWithheld))
|
|
||||||
)(this.subtotal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,20 +5,12 @@ import CustomViewBaseModel from './CustomViewBaseModel';
|
|||||||
import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants';
|
import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import CreditNoteMeta from './CreditNote.Meta';
|
import CreditNoteMeta from './CreditNote.Meta';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
|
|
||||||
export default class CreditNote extends mixin(TenantModel, [
|
export default class CreditNote extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
public amount: number;
|
|
||||||
public exchangeRate: number;
|
|
||||||
public openedAt: Date;
|
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
public adjustment: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -43,21 +35,8 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
'isPublished',
|
'isPublished',
|
||||||
'isOpen',
|
'isOpen',
|
||||||
'isClosed',
|
'isClosed',
|
||||||
|
|
||||||
'creditsRemaining',
|
'creditsRemaining',
|
||||||
'creditsUsed',
|
'creditsUsed',
|
||||||
|
|
||||||
'subtotal',
|
|
||||||
'subtotalLocal',
|
|
||||||
|
|
||||||
'discountAmount',
|
|
||||||
'discountAmountLocal',
|
|
||||||
'discountPercentage',
|
|
||||||
|
|
||||||
'total',
|
|
||||||
'totalLocal',
|
|
||||||
|
|
||||||
'adjustmentLocal',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,72 +48,6 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Credit note subtotal.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotal() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Credit note subtotal in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotalLocal() {
|
|
||||||
return this.subtotal * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmountLocal() {
|
|
||||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjustment amount in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get adjustmentLocal() {
|
|
||||||
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Credit note total.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get total() {
|
|
||||||
return this.subtotal - this.discountAmount + this.adjustment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Credit note total in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get totalLocal() {
|
|
||||||
return this.total * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the credit note is draft.
|
* Detarmines whether the credit note is draft.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@@ -263,7 +176,6 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
const Warehouse = require('models/Warehouse');
|
const Warehouse = require('models/Warehouse');
|
||||||
const { PdfTemplate } = require('models/PdfTemplate');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -354,18 +266,6 @@ export default class CreditNote extends mixin(TenantModel, [
|
|||||||
query.where('model_ref', 'CreditNote');
|
query.where('model_ref', 'CreditNote');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Credit note may belongs to pdf branding template.
|
|
||||||
*/
|
|
||||||
pdfTemplate: {
|
|
||||||
relation: Model.BelongsToOneRelation,
|
|
||||||
modelClass: PdfTemplate,
|
|
||||||
join: {
|
|
||||||
from: 'credit_notes.pdfTemplateId',
|
|
||||||
to: 'pdf_templates.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ export default {
|
|||||||
name: 'item.field.note',
|
name: 'item.field.note',
|
||||||
fieldType: 'text',
|
fieldType: 'text',
|
||||||
},
|
},
|
||||||
categoryId: {
|
category: {
|
||||||
name: 'item.field.category',
|
name: 'item.field.category',
|
||||||
fieldType: 'relation',
|
fieldType: 'relation',
|
||||||
relationModel: 'ItemCategory',
|
relationModel: 'ItemCategory',
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import { Model } from 'objection';
|
import { Model } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
|
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
|
|
||||||
// Subtotal (qty * rate) (tax inclusive)
|
|
||||||
// Subtotal Tax Exclusive (Subtotal - Tax Amount)
|
|
||||||
// Discount (Is percentage ? amount * discount : discount)
|
|
||||||
// Total (Subtotal - Discount)
|
|
||||||
|
|
||||||
export default class ItemEntry extends TenantModel {
|
export default class ItemEntry extends TenantModel {
|
||||||
public taxRate: number;
|
public taxRate: number;
|
||||||
@@ -14,7 +8,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
public quantity: number;
|
public quantity: number;
|
||||||
public rate: number;
|
public rate: number;
|
||||||
public isInclusiveTax: number;
|
public isInclusiveTax: number;
|
||||||
public discountType: DiscountType;
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
@@ -37,24 +31,10 @@ export default class ItemEntry extends TenantModel {
|
|||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return [
|
||||||
// Amount (qty * rate)
|
|
||||||
'amount',
|
'amount',
|
||||||
|
|
||||||
'taxAmount',
|
'taxAmount',
|
||||||
|
'amountExludingTax',
|
||||||
// Subtotal (qty * rate) + (tax inclusive)
|
'amountInclusingTax',
|
||||||
'subtotalInclusingTax',
|
|
||||||
|
|
||||||
// Subtotal Tax Exclusive (Subtotal - Tax Amount)
|
|
||||||
'subtotalExcludingTax',
|
|
||||||
|
|
||||||
// Subtotal (qty * rate) + (tax inclusive)
|
|
||||||
'subtotal',
|
|
||||||
|
|
||||||
// Discount (Is percentage ? amount * discount : discount)
|
|
||||||
'discountAmount',
|
|
||||||
|
|
||||||
// Total (Subtotal - Discount)
|
|
||||||
'total',
|
'total',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -65,15 +45,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
return this.subtotal - this.discountAmount;
|
return this.amountInclusingTax;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total (excluding tax).
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get totalExcludingTax() {
|
|
||||||
return this.subtotalExcludingTax - this.discountAmount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,27 +57,19 @@ export default class ItemEntry extends TenantModel {
|
|||||||
return this.quantity * this.rate;
|
return this.quantity * this.rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtotal amount (tax inclusive).
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotal() {
|
|
||||||
return this.subtotalInclusingTax;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item entry amount including tax.
|
* Item entry amount including tax.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get subtotalInclusingTax() {
|
get amountInclusingTax() {
|
||||||
return this.isInclusiveTax ? this.amount : this.amount + this.taxAmount;
|
return this.isInclusiveTax ? this.amount : this.amount + this.taxAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtotal amount (tax exclusive).
|
* Item entry amount excluding tax.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get subtotalExcludingTax() {
|
get amountExludingTax() {
|
||||||
return this.isInclusiveTax ? this.amount - this.taxAmount : this.amount;
|
return this.isInclusiveTax ? this.amount - this.taxAmount : this.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,9 +78,7 @@ export default class ItemEntry extends TenantModel {
|
|||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get discountAmount() {
|
get discountAmount() {
|
||||||
return this.discountType === DiscountType.Percentage
|
return this.amount * (this.discount / 100);
|
||||||
? this.amount * (this.discount / 100)
|
|
||||||
: this.discount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import { Model } from 'objection';
|
|
||||||
import TenantModel from 'models/TenantModel';
|
|
||||||
|
|
||||||
export class PaymentIntegration extends Model {
|
|
||||||
paymentEnabled!: boolean;
|
|
||||||
payoutEnabled!: boolean;
|
|
||||||
|
|
||||||
static get tableName() {
|
|
||||||
return 'payment_integrations';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get idColumn() {
|
|
||||||
return 'id';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return ['fullEnabled'];
|
|
||||||
}
|
|
||||||
|
|
||||||
static get jsonAttributes() {
|
|
||||||
return ['options'];
|
|
||||||
}
|
|
||||||
|
|
||||||
get fullEnabled() {
|
|
||||||
return this.paymentEnabled && this.payoutEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get modifiers() {
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Query to filter enabled payment and payout.
|
|
||||||
*/
|
|
||||||
fullEnabled(query) {
|
|
||||||
query.where('paymentEnabled', true).andWhere('payoutEnabled', true);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static get jsonSchema() {
|
|
||||||
return {
|
|
||||||
type: 'object',
|
|
||||||
required: ['name', 'service'],
|
|
||||||
properties: {
|
|
||||||
id: { type: 'integer' },
|
|
||||||
service: { type: 'string' },
|
|
||||||
paymentEnabled: { type: 'boolean' },
|
|
||||||
payoutEnabled: { type: 'boolean' },
|
|
||||||
accountId: { type: 'string' },
|
|
||||||
options: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
bankAccountId: { type: 'number' },
|
|
||||||
clearingAccountId: { type: 'number' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
createdAt: { type: 'string', format: 'date-time' },
|
|
||||||
updatedAt: { type: 'string', format: 'date-time' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,10 +11,6 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
amount!: number;
|
|
||||||
paymentAmount!: number;
|
|
||||||
exchangeRate!: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name.
|
* Table name.
|
||||||
*/
|
*/
|
||||||
@@ -33,7 +29,7 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return ['localAmount', 'total'];
|
return ['localAmount'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,14 +40,6 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Payment receive total.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get total() {
|
|
||||||
return this.paymentAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resourcable model.
|
* Resourcable model.
|
||||||
*/
|
*/
|
||||||
@@ -69,7 +57,6 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
const Account = require('models/Account');
|
const Account = require('models/Account');
|
||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
const { PdfTemplate } = require('models/PdfTemplate');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customer: {
|
customer: {
|
||||||
@@ -144,18 +131,6 @@ export default class PaymentReceive extends mixin(TenantModel, [
|
|||||||
query.where('model_ref', 'PaymentReceive');
|
query.where('model_ref', 'PaymentReceive');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Payment received may belongs to pdf branding template.
|
|
||||||
*/
|
|
||||||
pdfTemplate: {
|
|
||||||
relation: Model.BelongsToOneRelation,
|
|
||||||
modelClass: PdfTemplate,
|
|
||||||
join: {
|
|
||||||
from: 'payment_receives.pdfTemplateId',
|
|
||||||
to: 'pdf_templates.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
import { getUploadedObjectUri } from '@/services/Attachments/utils';
|
|
||||||
import TenantModel from 'models/TenantModel';
|
|
||||||
|
|
||||||
export class PdfTemplate extends TenantModel {
|
|
||||||
public readonly attributes: Record<string, any>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table name.
|
|
||||||
*/
|
|
||||||
static get tableName() {
|
|
||||||
return 'pdf_templates';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamps columns.
|
|
||||||
*/
|
|
||||||
get timestamps() {
|
|
||||||
return ['createdAt', 'updatedAt'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Json schema.
|
|
||||||
*/
|
|
||||||
static get jsonSchema() {
|
|
||||||
return {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
id: { type: 'integer' },
|
|
||||||
templateName: { type: 'string' },
|
|
||||||
attributes: { type: 'object' }, // JSON field definition
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model modifiers.
|
|
||||||
*/
|
|
||||||
static get modifiers() {
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Filters the due invoices.
|
|
||||||
*/
|
|
||||||
default(query) {
|
|
||||||
query.where('default', true);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Virtual attributes.
|
|
||||||
*/
|
|
||||||
static get virtualAttributes() {
|
|
||||||
return ['companyLogoUri'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the company logo uri.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
get companyLogoUri() {
|
|
||||||
return this.attributes?.companyLogoKey
|
|
||||||
? getUploadedObjectUri(this.attributes.companyLogoKey)
|
|
||||||
: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relationship mapping.
|
|
||||||
*/
|
|
||||||
static get relationMappings() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,30 +7,12 @@ import ModelSetting from './ModelSetting';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Estimates/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Estimates/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
import { defaultTo } from 'lodash';
|
|
||||||
|
|
||||||
export default class SaleEstimate extends mixin(TenantModel, [
|
export default class SaleEstimate extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
public amount: number;
|
|
||||||
public exchangeRate: number;
|
|
||||||
|
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
|
|
||||||
public adjustment: number;
|
|
||||||
|
|
||||||
public expirationDate!: string;
|
|
||||||
public deliveredAt!: string | null;
|
|
||||||
public approvedAt!: string | null;
|
|
||||||
public rejectedAt!: string | null;
|
|
||||||
|
|
||||||
public convertedToInvoiceId!: number | null;
|
|
||||||
public convertedToInvoiceAt!: string | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -51,12 +33,6 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return [
|
||||||
'localAmount',
|
'localAmount',
|
||||||
'discountAmount',
|
|
||||||
'discountPercentage',
|
|
||||||
'total',
|
|
||||||
'totalLocal',
|
|
||||||
'subtotal',
|
|
||||||
'subtotalLocal',
|
|
||||||
'isDelivered',
|
'isDelivered',
|
||||||
'isExpired',
|
'isExpired',
|
||||||
'isConvertedToInvoice',
|
'isConvertedToInvoice',
|
||||||
@@ -73,60 +49,6 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Estimate subtotal.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotal() {
|
|
||||||
return this.amount;;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Estimate subtotal in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotalLocal() {
|
|
||||||
return this.localAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage
|
|
||||||
? this.discount
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Estimate total.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get total() {
|
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
|
||||||
|
|
||||||
return this.subtotal - this.discountAmount + adjustmentAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Estimate total in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get totalLocal() {
|
|
||||||
return this.total * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines whether the sale estimate converted to sale invoice.
|
* Detarmines whether the sale estimate converted to sale invoice.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
@@ -262,7 +184,6 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
const Branch = require('models/Branch');
|
const Branch = require('models/Branch');
|
||||||
const Warehouse = require('models/Warehouse');
|
const Warehouse = require('models/Warehouse');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
const { PdfTemplate } = require('models/PdfTemplate');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customer: {
|
customer: {
|
||||||
@@ -331,18 +252,6 @@ export default class SaleEstimate extends mixin(TenantModel, [
|
|||||||
query.where('model_ref', 'SaleEstimate');
|
query.where('model_ref', 'SaleEstimate');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Sale estimate may belongs to pdf branding template.
|
|
||||||
*/
|
|
||||||
pdfTemplate: {
|
|
||||||
relation: Model.BelongsToOneRelation,
|
|
||||||
modelClass: PdfTemplate,
|
|
||||||
join: {
|
|
||||||
from: 'sales_estimates.pdfTemplateId',
|
|
||||||
to: 'pdf_templates.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { mixin, Model, raw } from 'objection';
|
import { mixin, Model, raw } from 'objection';
|
||||||
import * as R from 'ramda';
|
import { castArray, takeWhile } from 'lodash';
|
||||||
import { castArray, defaultTo, takeWhile } from 'lodash';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
import ModelSetting from './ModelSetting';
|
import ModelSetting from './ModelSetting';
|
||||||
@@ -8,7 +7,6 @@ import SaleInvoiceMeta from './SaleInvoice.Settings';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Invoices/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Invoices/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
|
|
||||||
export default class SaleInvoice extends mixin(TenantModel, [
|
export default class SaleInvoice extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
@@ -25,9 +23,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
public writtenoffAt: Date;
|
public writtenoffAt: Date;
|
||||||
public dueDate: Date;
|
public dueDate: Date;
|
||||||
public deliveredAt: Date;
|
public deliveredAt: Date;
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
public adjustment: number | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
@@ -72,15 +67,10 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
'subtotalExludingTax',
|
'subtotalExludingTax',
|
||||||
|
|
||||||
'taxAmountWithheldLocal',
|
'taxAmountWithheldLocal',
|
||||||
'discountAmount',
|
|
||||||
'discountAmountLocal',
|
|
||||||
'discountPercentage',
|
|
||||||
|
|
||||||
'total',
|
'total',
|
||||||
'totalLocal',
|
'totalLocal',
|
||||||
|
|
||||||
'writtenoffAmountLocal',
|
'writtenoffAmountLocal',
|
||||||
'adjustmentLocal',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,52 +125,14 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
return this.taxAmountWithheld * this.exchangeRate;
|
return this.taxAmountWithheld * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local discount amount.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountAmountLocal() {
|
|
||||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjustment amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get adjustmentLocal(): number | null {
|
|
||||||
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice total. (Tax included)
|
* Invoice total. (Tax included)
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
get total() {
|
get total() {
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
return this.isInclusiveTax
|
||||||
|
? this.subtotal
|
||||||
return R.compose(
|
: this.subtotal + this.taxAmountWithheld;
|
||||||
R.add(adjustmentAmount),
|
|
||||||
R.subtract(R.__, this.discountAmount),
|
|
||||||
R.when(R.always(this.isInclusiveTax), R.add(this.taxAmountWithheld))
|
|
||||||
)(this.subtotal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -461,10 +413,6 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
const TaxRateTransaction = require('models/TaxRateTransaction');
|
const TaxRateTransaction = require('models/TaxRateTransaction');
|
||||||
const Document = require('models/Document');
|
const Document = require('models/Document');
|
||||||
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
||||||
const {
|
|
||||||
TransactionPaymentServiceEntry,
|
|
||||||
} = require('models/TransactionPaymentServiceEntry');
|
|
||||||
const { PdfTemplate } = require('models/PdfTemplate');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -561,7 +509,7 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
join: {
|
join: {
|
||||||
from: 'sales_invoices.warehouseId',
|
from: 'sales_invoices.warehouseId',
|
||||||
to: 'warehouses.id',
|
to: 'warehouses.id',
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -618,42 +566,12 @@ export default class SaleInvoice extends mixin(TenantModel, [
|
|||||||
modelClass: MatchedBankTransaction,
|
modelClass: MatchedBankTransaction,
|
||||||
join: {
|
join: {
|
||||||
from: 'sales_invoices.id',
|
from: 'sales_invoices.id',
|
||||||
to: 'matched_bank_transactions.referenceId',
|
to: "matched_bank_transactions.referenceId",
|
||||||
},
|
},
|
||||||
filter(query) {
|
filter(query) {
|
||||||
query.where('reference_type', 'SaleInvoice');
|
query.where('reference_type', 'SaleInvoice');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Sale invoice may belongs to payment methods entries.
|
|
||||||
*/
|
|
||||||
paymentMethods: {
|
|
||||||
relation: Model.HasManyRelation,
|
|
||||||
modelClass: TransactionPaymentServiceEntry,
|
|
||||||
join: {
|
|
||||||
from: 'sales_invoices.id',
|
|
||||||
to: 'transactions_payment_methods.referenceId',
|
|
||||||
},
|
|
||||||
beforeInsert: (model) => {
|
|
||||||
model.referenceType = 'SaleInvoice';
|
|
||||||
},
|
|
||||||
filter: (query) => {
|
|
||||||
query.where('reference_type', 'SaleInvoice');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sale invoice may belongs to pdf branding template.
|
|
||||||
*/
|
|
||||||
pdfTemplate: {
|
|
||||||
relation: Model.BelongsToOneRelation,
|
|
||||||
modelClass: PdfTemplate,
|
|
||||||
join: {
|
|
||||||
from: 'sales_invoices.pdfTemplateId',
|
|
||||||
to: 'pdf_templates.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,23 +5,12 @@ import SaleReceiptSettings from './SaleReceipt.Settings';
|
|||||||
import CustomViewBaseModel from './CustomViewBaseModel';
|
import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
import { DEFAULT_VIEWS } from '@/services/Sales/Receipts/constants';
|
import { DEFAULT_VIEWS } from '@/services/Sales/Receipts/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
import { defaultTo } from 'lodash';
|
|
||||||
|
|
||||||
export default class SaleReceipt extends mixin(TenantModel, [
|
export default class SaleReceipt extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
public amount: number;
|
|
||||||
public exchangeRate: number;
|
|
||||||
public closedAt: Date;
|
|
||||||
|
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
|
|
||||||
public adjustment: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
@@ -40,28 +29,7 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return ['localAmount', 'isClosed', 'isDraft'];
|
||||||
'localAmount',
|
|
||||||
|
|
||||||
'subtotal',
|
|
||||||
'subtotalLocal',
|
|
||||||
|
|
||||||
'total',
|
|
||||||
'totalLocal',
|
|
||||||
|
|
||||||
'adjustment',
|
|
||||||
'adjustmentLocal',
|
|
||||||
|
|
||||||
'discountAmount',
|
|
||||||
'discountAmountLocal',
|
|
||||||
'discountPercentage',
|
|
||||||
|
|
||||||
'paid',
|
|
||||||
'paidLocal',
|
|
||||||
|
|
||||||
'isClosed',
|
|
||||||
'isDraft',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,90 +40,6 @@ export default class SaleReceipt extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt subtotal.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotal() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt subtotal in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotalLocal() {
|
|
||||||
return this.localAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountAmountLocal() {
|
|
||||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt total.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get total() {
|
|
||||||
const adjustmentAmount = defaultTo(this.adjustment, 0);
|
|
||||||
|
|
||||||
return this.subtotal - this.discountAmount + adjustmentAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt total in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get totalLocal() {
|
|
||||||
return this.total * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjustment amount in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get adjustmentLocal() {
|
|
||||||
return this.adjustment * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt paid amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get paid() {
|
|
||||||
return this.total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receipt paid amount in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get paidLocal() {
|
|
||||||
return this.paid * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmine whether the sale receipt closed.
|
* Detarmine whether the sale receipt closed.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import TenantModel from 'models/TenantModel';
|
|
||||||
|
|
||||||
export class TransactionPaymentServiceEntry extends TenantModel {
|
|
||||||
/**
|
|
||||||
* Table name
|
|
||||||
*/
|
|
||||||
static get tableName() {
|
|
||||||
return 'transactions_payment_methods';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Json schema of the model.
|
|
||||||
*/
|
|
||||||
static get jsonSchema() {
|
|
||||||
return {
|
|
||||||
type: 'object',
|
|
||||||
required: ['paymentIntegrationId'],
|
|
||||||
properties: {
|
|
||||||
id: { type: 'integer' },
|
|
||||||
referenceId: { type: 'integer' },
|
|
||||||
referenceType: { type: 'string' },
|
|
||||||
paymentIntegrationId: { type: 'integer' },
|
|
||||||
enable: { type: 'boolean' },
|
|
||||||
options: { type: 'object' },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relationship mapping.
|
|
||||||
*/
|
|
||||||
static get relationMappings() {
|
|
||||||
const { PaymentIntegration } = require('./PaymentIntegration');
|
|
||||||
|
|
||||||
return {
|
|
||||||
paymentIntegration: {
|
|
||||||
relation: TenantModel.BelongsToOneRelation,
|
|
||||||
modelClass: PaymentIntegration,
|
|
||||||
join: {
|
|
||||||
from: 'transactions_payment_methods.paymentIntegrationId',
|
|
||||||
to: 'payment_integrations.id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,12 +11,6 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
) {
|
) {
|
||||||
id!: number;
|
id!: number;
|
||||||
date!: Date | string;
|
date!: Date | string;
|
||||||
|
|
||||||
/**
|
|
||||||
* Transaction amount.
|
|
||||||
* Negative represents to spending and positive to deposit/card charge.
|
|
||||||
* @param {number}
|
|
||||||
*/
|
|
||||||
amount!: number;
|
amount!: number;
|
||||||
categorized!: boolean;
|
categorized!: boolean;
|
||||||
accountId!: number;
|
accountId!: number;
|
||||||
|
|||||||
@@ -6,26 +6,26 @@ import CustomViewBaseModel from './CustomViewBaseModel';
|
|||||||
import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants';
|
import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants';
|
||||||
import ModelSearchable from './ModelSearchable';
|
import ModelSearchable from './ModelSearchable';
|
||||||
import VendorCreditMeta from './VendorCredit.Meta';
|
import VendorCreditMeta from './VendorCredit.Meta';
|
||||||
import { DiscountType } from '@/interfaces';
|
|
||||||
|
|
||||||
export default class VendorCredit extends mixin(TenantModel, [
|
export default class VendorCredit extends mixin(TenantModel, [
|
||||||
ModelSetting,
|
ModelSetting,
|
||||||
CustomViewBaseModel,
|
CustomViewBaseModel,
|
||||||
ModelSearchable,
|
ModelSearchable,
|
||||||
]) {
|
]) {
|
||||||
public amount: number;
|
|
||||||
public exchangeRate: number;
|
|
||||||
public openedAt: Date;
|
|
||||||
public discount: number;
|
|
||||||
public discountType: DiscountType;
|
|
||||||
public adjustment: number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table name
|
* Table name
|
||||||
*/
|
*/
|
||||||
static get tableName() {
|
static get tableName() {
|
||||||
return 'vendor_credits';
|
return 'vendor_credits';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual attributes.
|
||||||
|
*/
|
||||||
|
static get virtualAttributes() {
|
||||||
|
return ['localAmount'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendor credit amount in local currency.
|
* Vendor credit amount in local currency.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
@@ -34,72 +34,6 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
return this.amount * this.exchangeRate;
|
return this.amount * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Vendor credit subtotal.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotal() {
|
|
||||||
return this.amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vendor credit subtotal in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get subtotalLocal() {
|
|
||||||
return this.subtotal * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get discountAmount() {
|
|
||||||
return this.discountType === DiscountType.Amount
|
|
||||||
? this.discount
|
|
||||||
: this.subtotal * (this.discount / 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountAmountLocal() {
|
|
||||||
return this.discountAmount ? this.discountAmount * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Discount percentage.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get discountPercentage(): number | null {
|
|
||||||
return this.discountType === DiscountType.Percentage ? this.discount : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjustment amount in local currency.
|
|
||||||
* @returns {number | null}
|
|
||||||
*/
|
|
||||||
get adjustmentLocal() {
|
|
||||||
return this.adjustment ? this.adjustment * this.exchangeRate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vendor credit total.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get total() {
|
|
||||||
return this.subtotal - this.discountAmount + this.adjustment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vendor credit total in local currency.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
get totalLocal() {
|
|
||||||
return this.total * this.exchangeRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model modifiers.
|
* Model modifiers.
|
||||||
*/
|
*/
|
||||||
@@ -186,24 +120,7 @@ export default class VendorCredit extends mixin(TenantModel, [
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return [
|
return ['isDraft', 'isPublished', 'isOpen', 'isClosed', 'creditsRemaining'];
|
||||||
'isDraft',
|
|
||||||
'isPublished',
|
|
||||||
'isOpen',
|
|
||||||
'isClosed',
|
|
||||||
|
|
||||||
'creditsRemaining',
|
|
||||||
'localAmount',
|
|
||||||
|
|
||||||
'discountAmount',
|
|
||||||
'discountAmountLocal',
|
|
||||||
'discountPercentage',
|
|
||||||
|
|
||||||
'adjustmentLocal',
|
|
||||||
|
|
||||||
'total',
|
|
||||||
'totalLocal',
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,12 +3,7 @@ import TenantRepository from '@/repositories/TenantRepository';
|
|||||||
import { IAccount } from '@/interfaces';
|
import { IAccount } from '@/interfaces';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import {
|
import {
|
||||||
DiscountExpenseAccount,
|
|
||||||
OtherChargesAccount,
|
|
||||||
OtherExpensesAccount,
|
|
||||||
PrepardExpenses,
|
PrepardExpenses,
|
||||||
PurchaseDiscountAccount,
|
|
||||||
StripeClearingAccount,
|
|
||||||
TaxPayableAccount,
|
TaxPayableAccount,
|
||||||
UnearnedRevenueAccount,
|
UnearnedRevenueAccount,
|
||||||
} from '@/database/seeds/data/accounts';
|
} from '@/database/seeds/data/accounts';
|
||||||
@@ -192,9 +187,9 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or creates the unearned revenue.
|
* Finds or creates the unearned revenue.
|
||||||
* @param {Record<string, string>} extraAttrs
|
* @param {Record<string, string>} extraAttrs
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async findOrCreateUnearnedRevenue(
|
public async findOrCreateUnearnedRevenue(
|
||||||
extraAttrs: Record<string, string> = {},
|
extraAttrs: Record<string, string> = {},
|
||||||
@@ -223,9 +218,9 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or creates the prepard expenses account.
|
* Finds or creates the prepard expenses account.
|
||||||
* @param {Record<string, string>} extraAttrs
|
* @param {Record<string, string>} extraAttrs
|
||||||
* @param {Knex.Transaction} trx
|
* @param {Knex.Transaction} trx
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async findOrCreatePrepardExpenses(
|
public async findOrCreatePrepardExpenses(
|
||||||
extraAttrs: Record<string, string> = {},
|
extraAttrs: Record<string, string> = {},
|
||||||
@@ -252,146 +247,4 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds or creates the stripe clearing account.
|
|
||||||
* @param {Record<string, string>} extraAttrs
|
|
||||||
* @param {Knex.Transaction} trx
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async findOrCreateStripeClearing(
|
|
||||||
extraAttrs: Record<string, string> = {},
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
) {
|
|
||||||
// Retrieves the given tenant metadata.
|
|
||||||
const tenantMeta = await TenantMetadata.query().findOne({
|
|
||||||
tenantId: this.tenantId,
|
|
||||||
});
|
|
||||||
const _extraAttrs = {
|
|
||||||
currencyCode: tenantMeta.baseCurrency,
|
|
||||||
...extraAttrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = await this.model
|
|
||||||
.query(trx)
|
|
||||||
.findOne({ slug: StripeClearingAccount.slug, ..._extraAttrs });
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
|
||||||
...StripeClearingAccount,
|
|
||||||
..._extraAttrs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds or creates the discount expense account.
|
|
||||||
* @param {Record<string, string>} extraAttrs
|
|
||||||
* @param {Knex.Transaction} trx
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async findOrCreateDiscountAccount(
|
|
||||||
extraAttrs: Record<string, string> = {},
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
) {
|
|
||||||
// Retrieves the given tenant metadata.
|
|
||||||
const tenantMeta = await TenantMetadata.query().findOne({
|
|
||||||
tenantId: this.tenantId,
|
|
||||||
});
|
|
||||||
const _extraAttrs = {
|
|
||||||
currencyCode: tenantMeta.baseCurrency,
|
|
||||||
...extraAttrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = await this.model
|
|
||||||
.query(trx)
|
|
||||||
.findOne({ slug: DiscountExpenseAccount.slug, ..._extraAttrs });
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
|
||||||
...DiscountExpenseAccount,
|
|
||||||
..._extraAttrs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findOrCreatePurchaseDiscountAccount(
|
|
||||||
extraAttrs: Record<string, string> = {},
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
) {
|
|
||||||
// Retrieves the given tenant metadata.
|
|
||||||
const tenantMeta = await TenantMetadata.query().findOne({
|
|
||||||
tenantId: this.tenantId,
|
|
||||||
});
|
|
||||||
const _extraAttrs = {
|
|
||||||
currencyCode: tenantMeta.baseCurrency,
|
|
||||||
...extraAttrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = await this.model
|
|
||||||
.query(trx)
|
|
||||||
.findOne({ slug: PurchaseDiscountAccount.slug, ..._extraAttrs });
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
|
||||||
...PurchaseDiscountAccount,
|
|
||||||
..._extraAttrs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findOrCreateOtherChargesAccount(
|
|
||||||
extraAttrs: Record<string, string> = {},
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
) {
|
|
||||||
// Retrieves the given tenant metadata.
|
|
||||||
const tenantMeta = await TenantMetadata.query().findOne({
|
|
||||||
tenantId: this.tenantId,
|
|
||||||
});
|
|
||||||
const _extraAttrs = {
|
|
||||||
currencyCode: tenantMeta.baseCurrency,
|
|
||||||
...extraAttrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = await this.model
|
|
||||||
.query(trx)
|
|
||||||
.findOne({ slug: OtherChargesAccount.slug, ..._extraAttrs });
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
|
||||||
...OtherChargesAccount,
|
|
||||||
..._extraAttrs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async findOrCreateOtherExpensesAccount(
|
|
||||||
extraAttrs: Record<string, string> = {},
|
|
||||||
trx?: Knex.Transaction
|
|
||||||
) {
|
|
||||||
// Retrieves the given tenant metadata.
|
|
||||||
const tenantMeta = await TenantMetadata.query().findOne({
|
|
||||||
tenantId: this.tenantId,
|
|
||||||
});
|
|
||||||
const _extraAttrs = {
|
|
||||||
currencyCode: tenantMeta.baseCurrency,
|
|
||||||
...extraAttrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = await this.model
|
|
||||||
.query(trx)
|
|
||||||
.findOne({ slug: OtherExpensesAccount.slug, ..._extraAttrs });
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
result = await this.model.query(trx).insertAndFetch({
|
|
||||||
...OtherExpensesAccount,
|
|
||||||
..._extraAttrs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,6 @@ export default class Ledger implements ILedger {
|
|||||||
return {
|
return {
|
||||||
credit: defaultTo(entry.credit, 0),
|
credit: defaultTo(entry.credit, 0),
|
||||||
debit: defaultTo(entry.debit, 0),
|
debit: defaultTo(entry.debit, 0),
|
||||||
|
|
||||||
exchangeRate: entry.exchangeRate,
|
exchangeRate: entry.exchangeRate,
|
||||||
currencyCode: entry.currencyCode,
|
currencyCode: entry.currencyCode,
|
||||||
|
|
||||||
|
|||||||
@@ -9,18 +9,15 @@ import {
|
|||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { transformLedgerEntryToTransaction } from './utils';
|
import { transformLedgerEntryToTransaction } from './utils';
|
||||||
|
|
||||||
// Filter the blank entries.
|
|
||||||
const filterBlankEntry = (entry: ILedgerEntry) => Boolean(entry.credit || entry.debit);
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class LedgerEntriesStorage {
|
export class LedgerEntriesStorage {
|
||||||
@Inject()
|
@Inject()
|
||||||
private tenancy: HasTenancyService;
|
tenancy: HasTenancyService;
|
||||||
/**
|
/**
|
||||||
* Saves entries of the given ledger.
|
* Saves entries of the given ledger.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {ILedger} ledger
|
* @param {ILedger} ledger
|
||||||
* @param {Knex.Transaction} knex
|
* @param {Knex.Transaction} knex
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public saveEntries = async (
|
public saveEntries = async (
|
||||||
@@ -29,7 +26,7 @@ export class LedgerEntriesStorage {
|
|||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction
|
||||||
) => {
|
) => {
|
||||||
const saveEntryQueue = async.queue(this.saveEntryTask, 10);
|
const saveEntryQueue = async.queue(this.saveEntryTask, 10);
|
||||||
const entries = ledger.filter(filterBlankEntry).getEntries();
|
const entries = ledger.getEntries();
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
saveEntryQueue.push({ tenantId, entry, trx });
|
saveEntryQueue.push({ tenantId, entry, trx });
|
||||||
@@ -60,8 +57,8 @@ export class LedgerEntriesStorage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the ledger entry to the account transactions repository.
|
* Saves the ledger entry to the account transactions repository.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {ILedgerEntry} entry
|
* @param {ILedgerEntry} entry
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
private saveEntry = async (
|
private saveEntry = async (
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ export class AccountTransformer extends Transformer {
|
|||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return [
|
return [
|
||||||
'accountTypeLabel',
|
|
||||||
'accountNormalFormatted',
|
|
||||||
'formattedAmount',
|
'formattedAmount',
|
||||||
'flattenName',
|
'flattenName',
|
||||||
'bankBalanceFormatted',
|
'bankBalanceFormatted',
|
||||||
@@ -86,22 +84,6 @@ export class AccountTransformer extends Transformer {
|
|||||||
return account.plaidItem?.isPaused || false;
|
return account.plaidItem?.isPaused || false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves formatted account type label.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
protected accountTypeLabel = (account: any): string => {
|
|
||||||
return this.context.i18n.__(account.accountTypeLabel);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves formatted account normal.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
protected accountNormalFormatted = (account: any): string => {
|
|
||||||
return this.context.i18n.__(account.accountNormalFormatted);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the accounts collection to flat or nested array.
|
* Transformes the accounts collection to flat or nested array.
|
||||||
* @param {IAccount[]}
|
* @param {IAccount[]}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
|
import I18nService from '@/services/I18n/I18nService';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import { AccountTransformer } from './AccountTransform';
|
import { AccountTransformer } from './AccountTransform';
|
||||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
|
||||||
import events from '@/subscribers/events';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class GetAccount {
|
export class GetAccount {
|
||||||
@@ -11,10 +10,10 @@ export class GetAccount {
|
|||||||
private tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private transformer: TransformerInjectable;
|
private i18nService: I18nService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private eventPublisher: EventPublisher;
|
private transformer: TransformerInjectable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the given account details.
|
* Retrieve the given account details.
|
||||||
@@ -40,11 +39,10 @@ export class GetAccount {
|
|||||||
new AccountTransformer(),
|
new AccountTransformer(),
|
||||||
{ accountsGraph }
|
{ accountsGraph }
|
||||||
);
|
);
|
||||||
const eventPayload = { tenantId, accountId };
|
return this.i18nService.i18nApply(
|
||||||
|
[['accountTypeLabel'], ['accountNormalFormatted']],
|
||||||
// Triggers `onAccountViewed` event.
|
transformed,
|
||||||
await this.eventPublisher.emitAsync(events.accounts.onViewed, eventPayload);
|
tenantId
|
||||||
|
);
|
||||||
return transformed;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import { NextFunction, Request, Response } from 'express';
|
|
||||||
import multer from 'multer';
|
import multer from 'multer';
|
||||||
import type { Multer } from 'multer';
|
import type { Multer } from 'multer';
|
||||||
import multerS3 from 'multer-s3';
|
import multerS3 from 'multer-s3';
|
||||||
import { s3 } from '@/lib/S3/S3';
|
import { s3 } from '@/lib/S3/S3';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class AttachmentUploadPipeline {
|
export class AttachmentUploadPipeline {
|
||||||
/**
|
/**
|
||||||
* Middleware to ensure that S3 configuration is properly set before proceeding.
|
* Middleware to ensure that S3 configuration is properly set before proceeding.
|
||||||
* This function checks if the necessary S3 configuration keys are present and throws an error if any are missing.
|
* This function checks if the necessary S3 configuration keys are present and throws an error if any are missing.
|
||||||
|
*
|
||||||
* @param req The HTTP request object.
|
* @param req The HTTP request object.
|
||||||
* @param res The HTTP response object.
|
* @param res The HTTP response object.
|
||||||
* @param next The callback to pass control to the next middleware function.
|
* @param next The callback to pass control to the next middleware function.
|
||||||
@@ -48,11 +49,6 @@ export class AttachmentUploadPipeline {
|
|||||||
key: function (req, file, cb) {
|
key: function (req, file, cb) {
|
||||||
cb(null, Date.now().toString());
|
cb(null, Date.now().toString());
|
||||||
},
|
},
|
||||||
acl: function(req, file, cb) {
|
|
||||||
// Conditionally set file to public or private based on isPublic flag
|
|
||||||
const aclValue = true ? 'public-read' : 'private';
|
|
||||||
cb(null, aclValue); // Set ACL based on the isPublic flag
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';
|
|||||||
import {
|
import {
|
||||||
ISaleInvoiceCreatedPayload,
|
ISaleInvoiceCreatedPayload,
|
||||||
ISaleInvoiceCreatingPaylaod,
|
ISaleInvoiceCreatingPaylaod,
|
||||||
ISaleInvoiceDeletingPayload,
|
ISaleInvoiceDeletePayload,
|
||||||
ISaleInvoiceEditedPayload,
|
ISaleInvoiceEditedPayload,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
@@ -146,13 +146,13 @@ export class AttachmentsOnSaleInvoiceCreated {
|
|||||||
*/
|
*/
|
||||||
private async handleUnlinkAttachmentsOnInvoiceDeleted({
|
private async handleUnlinkAttachmentsOnInvoiceDeleted({
|
||||||
tenantId,
|
tenantId,
|
||||||
oldSaleInvoice,
|
saleInvoice,
|
||||||
trx,
|
trx,
|
||||||
}: ISaleInvoiceDeletingPayload) {
|
}: ISaleInvoiceDeletePayload) {
|
||||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||||
tenantId,
|
tenantId,
|
||||||
'SaleInvoice',
|
'SaleInvoice',
|
||||||
oldSaleInvoice.id,
|
saleInvoice.id,
|
||||||
trx
|
trx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import path from 'path';
|
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
export const getUploadedObjectUri = (objectKey: string) => {
|
|
||||||
return new URL(
|
|
||||||
path.join(config.s3.bucket, objectKey),
|
|
||||||
config.s3.endpoint
|
|
||||||
).toString();
|
|
||||||
};
|
|
||||||
@@ -4,27 +4,11 @@ import {
|
|||||||
Institution as PlaidInstitution,
|
Institution as PlaidInstitution,
|
||||||
AccountBase as PlaidAccount,
|
AccountBase as PlaidAccount,
|
||||||
TransactionBase as PlaidTransactionBase,
|
TransactionBase as PlaidTransactionBase,
|
||||||
AccountType as PlaidAccountType,
|
|
||||||
} from 'plaid';
|
} from 'plaid';
|
||||||
import {
|
import {
|
||||||
CreateUncategorizedTransactionDTO,
|
CreateUncategorizedTransactionDTO,
|
||||||
IAccountCreateDTO,
|
IAccountCreateDTO,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the system account type from the given Plaid account type.
|
|
||||||
* @param {PlaidAccountType} plaidAccountType
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
const getAccountTypeFromPlaidAccountType = (
|
|
||||||
plaidAccountType: PlaidAccountType
|
|
||||||
) => {
|
|
||||||
if (plaidAccountType === PlaidAccountType.Credit) {
|
|
||||||
return ACCOUNT_TYPE.CREDIT_CARD;
|
|
||||||
}
|
|
||||||
return ACCOUNT_TYPE.BANK;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the Plaid account to create cashflow account DTO.
|
* Transformes the Plaid account to create cashflow account DTO.
|
||||||
@@ -44,7 +28,7 @@ export const transformPlaidAccountToCreateAccount = R.curry(
|
|||||||
code: '',
|
code: '',
|
||||||
description: plaidAccount.official_name,
|
description: plaidAccount.official_name,
|
||||||
currencyCode: plaidAccount.balances.iso_currency_code,
|
currencyCode: plaidAccount.balances.iso_currency_code,
|
||||||
accountType: getAccountTypeFromPlaidAccountType(plaidAccount.type),
|
accountType: 'cash',
|
||||||
active: true,
|
active: true,
|
||||||
bankBalance: plaidAccount.balances.current,
|
bankBalance: plaidAccount.balances.current,
|
||||||
accountMask: plaidAccount.mask,
|
accountMask: plaidAccount.mask,
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { ILedgerEntry, ICashflowTransaction } from '../../interfaces';
|
import {
|
||||||
import { transformCashflowTransactionType } from './utils';
|
ILedgerEntry,
|
||||||
|
ICashflowTransaction,
|
||||||
|
AccountNormal,
|
||||||
|
} from '../../interfaces';
|
||||||
|
import {
|
||||||
|
transformCashflowTransactionType,
|
||||||
|
getCashflowAccountTransactionsTypes,
|
||||||
|
} from './utils';
|
||||||
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
|
||||||
import Ledger from '@/services/Accounting/Ledger';
|
import Ledger from '@/services/Accounting/Ledger';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
@@ -63,7 +70,7 @@ export default class CashflowTransactionJournalEntries {
|
|||||||
debit: cashflowTransaction.isCashDebit
|
debit: cashflowTransaction.isCashDebit
|
||||||
? cashflowTransaction.localAmount
|
? cashflowTransaction.localAmount
|
||||||
: 0,
|
: 0,
|
||||||
accountNormal: cashflowTransaction?.cashflowAccount?.accountNormal,
|
accountNormal: AccountNormal.DEBIT,
|
||||||
index: 1,
|
index: 1,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -136,7 +143,6 @@ export default class CashflowTransactionJournalEntries {
|
|||||||
// Retrieves the cashflow transactions with associated entries.
|
// Retrieves the cashflow transactions with associated entries.
|
||||||
const transaction = await CashflowTransaction.query(trx)
|
const transaction = await CashflowTransaction.query(trx)
|
||||||
.findById(cashflowTransactionId)
|
.findById(cashflowTransactionId)
|
||||||
.withGraphFetched('cashflowAccount')
|
|
||||||
.withGraphFetched('creditAccount');
|
.withGraphFetched('creditAccount');
|
||||||
|
|
||||||
// Retrieves the cashflow transaction ledger.
|
// Retrieves the cashflow transaction ledger.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { CashflowAccountTransformer } from './CashflowAccountTransformer';
|
|||||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
|
||||||
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||||
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class GetCashflowAccountsService {
|
export default class GetCashflowAccountsService {
|
||||||
@@ -42,20 +41,14 @@ export default class GetCashflowAccountsService {
|
|||||||
const accounts = await CashflowAccount.query().onBuild((builder) => {
|
const accounts = await CashflowAccount.query().onBuild((builder) => {
|
||||||
dynamicList.buildQuery()(builder);
|
dynamicList.buildQuery()(builder);
|
||||||
|
|
||||||
builder.whereIn('account_type', [
|
builder.whereIn('account_type', ['bank', 'cash']);
|
||||||
ACCOUNT_TYPE.BANK,
|
|
||||||
ACCOUNT_TYPE.CASH,
|
|
||||||
ACCOUNT_TYPE.CREDIT_CARD,
|
|
||||||
]);
|
|
||||||
builder.modify('inactiveMode', filter.inactiveMode);
|
builder.modify('inactiveMode', filter.inactiveMode);
|
||||||
});
|
});
|
||||||
// Retrieves the transformed accounts.
|
// Retrieves the transformed accounts.
|
||||||
const transformed = await this.transformer.transform(
|
return this.transformer.transform(
|
||||||
tenantId,
|
tenantId,
|
||||||
accounts,
|
accounts,
|
||||||
new CashflowAccountTransformer()
|
new CashflowAccountTransformer()
|
||||||
);
|
);
|
||||||
|
|
||||||
return transformed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class GetCashflowTransactionService {
|
|||||||
private tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
private transformer: TransformerInjectable;
|
private transfromer: TransformerInjectable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the given cashflow transaction.
|
* Retrieve the given cashflow transaction.
|
||||||
@@ -37,7 +37,7 @@ export class GetCashflowTransactionService {
|
|||||||
this.throwErrorCashflowTranscationNotFound(cashflowTransaction);
|
this.throwErrorCashflowTranscationNotFound(cashflowTransaction);
|
||||||
|
|
||||||
// Transformes the cashflow transaction model to POJO.
|
// Transformes the cashflow transaction model to POJO.
|
||||||
return this.transformer.transform(
|
return this.transfromer.transform(
|
||||||
tenantId,
|
tenantId,
|
||||||
cashflowTransaction,
|
cashflowTransaction,
|
||||||
new CashflowTransactionTransformer()
|
new CashflowTransactionTransformer()
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ export default class NewCashflowTransactionService {
|
|||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {ICashflowOwnerContributionDTO} ownerContributionDTO
|
* @param {ICashflowOwnerContributionDTO} ownerContributionDTO
|
||||||
* @param {number} userId - User id.
|
* @param {number} userId - User id.
|
||||||
* @returns {Promise<ICashflowTransaction>}
|
|
||||||
*/
|
*/
|
||||||
public newCashflowTransaction = async (
|
public newCashflowTransaction = async (
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user