Compare commits

...

216 Commits

Author SHA1 Message Date
a.bouhuolia
91ff3fdccb Merge branch 'main' into develop 2022-04-05 06:08:54 +02:00
a.bouhuolia
edd37fff78 fix(PaymaentViaVocher): make the plan is fixed. 2022-04-05 06:06:02 +02:00
a.bouhuolia
679f7ce96c Merge branch 'develop' into main 2022-04-05 05:27:28 +02:00
Ahmed Bouhuolia
79b3ab9ec7 Update CHANGELOG.md 2022-04-05 05:26:48 +02:00
a.bouhuolia
e7158b7ba7 feat(i18n): add the missing arabic localization. 2022-04-05 05:25:26 +02:00
Ahmed Bouhuolia
569bc1c4a4 Merge pull request #49 from bigcapitalhq/billingplans
Billingplans
2022-04-05 05:16:28 +02:00
elforjani13
b880732087 feat: add billing plans. 2022-04-04 23:52:29 +02:00
elforjani13
b1e7720bd9 BIG-378: add Localize to invoice. 2022-04-04 17:58:39 +02:00
a.bouhuolia
5eb9968095 Merge branch 'develop' into main 2022-03-31 15:09:25 +02:00
Ahmed Bouhuolia
b0cf8f723f Merge pull request #47 from bigcapitalhq/BIG-354-validate-the-warehouse-transfer-quantity-should-be-above-zero
BIG-354: Validate the warehouse transfer.
2022-03-31 15:05:34 +02:00
Ahmed Bouhuolia
b0a826e62a Merge branch 'develop' into BIG-354-validate-the-warehouse-transfer-quantity-should-be-above-zero 2022-03-31 15:05:27 +02:00
elforjani13
6daa9f09a5 BIG-354: fix validate the warehouse transfer. 2022-03-31 14:58:36 +02:00
Ahmed Bouhuolia
f828d85880 Merge pull request #45 from bigcapitalhq/BIG-344-add-branch-details-to-manual-journal-and-expense-drawer-details
BIG-344: add branch to manual journal & expense.
2022-03-31 14:56:35 +02:00
elforjani13
46d895bef9 BIG-354: Validate the warehouse transfer. 2022-03-31 14:50:40 +02:00
Ahmed Bouhuolia
1fa26c7cb7 Merge pull request #46 from bigcapitalhq/BIG-278-fix-created-at-in-expense-details
BIG-278: add created_at in expense details.
2022-03-31 14:30:21 +02:00
a.bouhuolia
41d2fc63cb chore(Changelog): add the missing logs. 2022-03-31 14:08:22 +02:00
a.bouhuolia
4814a40fa9 Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop 2022-03-31 14:07:21 +02:00
a.bouhuolia
b903aa3eb2 dump v1.7.2 version with changelogs. 2022-03-31 14:07:17 +02:00
elforjani13
872b98fb0d BIG-278: add created_at in expense details. 2022-03-31 13:57:07 +02:00
elforjani13
b849bfaa95 BIG-344: add branch to manual journal & expense. 2022-03-31 13:39:15 +02:00
Ahmed Bouhuolia
756af3c4d3 Merge pull request #43 from bigcapitalhq/BIG-141-add-inactive-status-to-item-drawer-details
Big 141 add inactive status to item drawer details
2022-03-31 00:52:51 +02:00
Ahmed Bouhuolia
b935d13918 Merge branch 'develop' into BIG-141-add-inactive-status-to-item-drawer-details 2022-03-31 00:52:41 +02:00
Ahmed Bouhuolia
4aea9cb19b Merge pull request #41 from bigcapitalhq/BIG-356-add-localize-remove-line-entries
Big 356 add localize remove line entries
2022-03-31 00:51:38 +02:00
Ahmed Bouhuolia
d22212e6e3 Merge branch 'develop' into BIG-356-add-localize-remove-line-entries 2022-03-31 00:51:28 +02:00
Ahmed Bouhuolia
6a6ff16c48 Merge pull request #44 from bigcapitalhq/BIG-238-validate-bill-due-date-should-be-equal-or-bigger-than-bill-date
Big 238 validate bill due date should be equal or bigger than bill date
2022-03-31 00:49:31 +02:00
Ahmed Bouhuolia
d08894820d Merge pull request #39 from bigcapitalhq/BIG-354-validate-the-warehouse-transfer-quantity-should-be-above-zero
BIG-354: warehouse transfer validate.
2022-03-31 00:49:07 +02:00
elforjani13
2db32b8ee8 BIG-141: add inactive status to item details. 2022-03-30 17:17:23 +02:00
elforjani13
86c6de361b BIG-356: add localize remove line entries. 2022-03-30 16:34:51 +02:00
elforjani13
9bd13b0d46 BIG-355: remove expandable in item categories. 2022-03-30 16:31:34 +02:00
elforjani13
30b17d697f BIG-355: remove expandable in item categories. 2022-03-30 16:28:42 +02:00
elforjani13
ce674466fe BIG-238: Validate bill due date. 2022-03-30 15:09:11 +02:00
elforjani13
373a695c4c BIG-236: Validate estimate expiration date. 2022-03-30 15:06:58 +02:00
elforjani13
3f4ffdc995 BIG-237: Validate invoice due date. 2022-03-30 15:04:55 +02:00
elforjani13
a9c2a5c5f0 BIG-354: warehouse transfer validate. 2022-03-28 21:38:56 +02:00
a.bouhuolia
908d232cb9 Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop 2022-03-28 19:26:09 +02:00
a.bouhuolia
10af33f1dc fix: BIG-352 Add terms and conditions/notes field to a warehouse transfer. 2022-03-28 19:25:06 +02:00
a.bouhuolia
767d807490 fix: BIG-352 Add terms and conditions/notes field to a warehouse transfer. 2022-03-28 19:06:38 +02:00
Ahmed Bouhuolia
ba1d945dca Merge pull request #38 from bigcapitalhq/BIG-284-cash-flow-statement-loading-bar-not-working
BIG-284: cash flow statement loading bar.
2022-03-28 16:23:42 +02:00
elforjani13
03ea8643e7 BIG-284: cash flow statment loading bar. 2022-03-28 16:18:54 +02:00
Ahmed Bouhuolia
3d78e5d397 Merge pull request #36 from bigcapitalhq/BIG-301-fix-navbar-divider-in-action-bar-detail-casl-ability
fix: navbar divider.
2022-03-28 16:07:20 +02:00
Ahmed Bouhuolia
fffd255eb1 Merge pull request #37 from bigcapitalhq/BIG-add-keepPreviousData
BIG: add keepPreviousData option on use query.
2022-03-28 16:05:42 +02:00
Ahmed Bouhuolia
d0f09a0164 Merge pull request #34 from bigcapitalhq/BIG-351-invalid-date-in-the-inventory-adjustment-detail
Big 351 invalid date in the inventory adjustment detail
2022-03-28 16:01:37 +02:00
elforjani13
7774d9f5ab BIG: add keepPreviousData . 2022-03-28 16:01:07 +02:00
Ahmed Bouhuolia
e5ab240dfd Merge pull request #33 from bigcapitalhq/BIG-221-remove-non-inventory-radio-choice-on-item-form
BIG-221: remove non inventory radio.
2022-03-28 15:54:59 +02:00
elforjani13
2b07917399 BIG-352: invalid date. 2022-03-28 15:48:36 +02:00
elforjani13
79099e1abc BIG-280: optimize select. 2022-03-28 15:46:37 +02:00
elforjani13
e87b22801b BIG-221: remove non inventory radio. 2022-03-28 13:46:41 +02:00
elforjani13
e0eaa56b5c fix: navbar divider. 2022-03-28 13:26:21 +02:00
a.bouhuolia
d842722183 fix: add the missed imported warehouse transfers. 2022-03-28 12:08:53 +02:00
a.bouhuolia
9c14f10edf Merge branch 'develop' of https://github.com/bigcapitalhq/client into develop 2022-03-28 12:01:39 +02:00
a.bouhuolia
6a8137729f fix(Account): BIG-296 Issue when creating a new child account from chart of accounts list. 2022-03-28 12:01:29 +02:00
a.bouhuolia
5c601fcf2d fix(Account): BIG-296 Issue when creating a new child account from chart of accounts list. 2022-03-28 11:58:12 +02:00
a.bouhuolia
df4c4a832b Merge branch 'develop' into main 2022-03-24 15:32:30 +02:00
elforjani13
86cab7988c feat: handle item error. 2022-03-24 15:03:25 +02:00
Ahmed Bouhuolia
8404fee10a dump v1.7.0-rc.1 2022-03-24 13:12:14 +02:00
elforjani13
99a23889bc feat: add warehouses transfers query. 2022-03-24 12:19:46 +02:00
elforjani13
5e2000d252 feat: add invalidate item warehouses. 2022-03-24 11:50:06 +02:00
a.bouhuolia
73cb0ec32e feat(InventoryItemDetail): Location query. 2022-03-23 21:28:13 +02:00
a.bouhuolia
8fc11b3237 feat(InventoryValuation): location query. 2022-03-23 21:26:19 +02:00
a.bouhuolia
eecb81e882 feat(JournalSheet): location query. 2022-03-23 18:34:19 +02:00
a.bouhuolia
2e743f2232 feat(GeneralLedger): location query. 2022-03-23 18:18:34 +02:00
a.bouhuolia
3faa765a07 feat(TrialBalance): location query. 2022-03-23 18:18:08 +02:00
a.bouhuolia
a6d93170df fix(BalanceSheet): filter by branches.
fix(ProfitLossSheet): filter by branches.
fix(CashflowStatement): filter by branches.
2022-03-23 16:47:22 +02:00
Ahmed Bouhuolia
3d9b95cbcf Merge pull request #31 from bigcapitalhq/feature/multi-dimensions
Implement foreign currency and multiply warehouses, branches.
2022-03-23 12:12:50 +02:00
Ahmed Bouhuolia
4882afd63f Merge branch 'develop' into feature/multi-dimensions 2022-03-23 12:12:20 +02:00
elforjani13
8dac7e3d98 fix: localization. 2022-03-23 00:30:21 +02:00
elforjani13
6e6b005fc9 fix: reports. 2022-03-23 00:11:04 +02:00
elforjani13
68323486e2 fix: items query. 2022-03-23 00:10:45 +02:00
elforjani13
fd357196a8 fix: warehouse transfer. 2022-03-23 00:10:05 +02:00
elforjani13
5a508dd789 fix: customer/vendor opening balance . 2022-03-23 00:09:08 +02:00
elforjani13
bac6812d36 fix: branch & warehouse activate. 2022-03-23 00:08:16 +02:00
elforjani13
ba71679b55 Fix: expenses. 2022-03-23 00:07:16 +02:00
elforjani13
bc0f4f4cd9 Fix: make journal. 2022-03-23 00:04:13 +02:00
elforjani13
4e53b3a2d5 Fix: purchases. 2022-03-22 23:59:05 +02:00
elforjani13
a913b84723 Fix: sales. 2022-03-22 23:58:03 +02:00
elforjani13
50f1979c9f Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-21 20:13:34 +02:00
elforjani13
3722afdc47 feat(customer & vendor detail): localization. 2022-03-21 20:13:07 +02:00
a.bouhuolia
5711fb8366 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-21 20:10:20 +02:00
a.bouhuolia
09f4d0fbe0 feat(Warehouses|Branches): highlight the primary warehouses and branches. 2022-03-21 20:10:10 +02:00
elforjani13
918780bf4c Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-21 20:03:52 +02:00
elforjani13
8b78fbdb86 feat(branch & warehouse activate): localization. 2022-03-21 20:03:18 +02:00
a.bouhuolia
2c0291da84 fix(ExchangeRateMutatedField): optimize style. 2022-03-21 19:46:30 +02:00
a.bouhuolia
a17fafbc90 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-21 18:32:05 +02:00
a.bouhuolia
701c32debd feat(Warehouses|Branches): empty status text. 2022-03-21 18:31:31 +02:00
elforjani13
70e1e94a4a fix(form footer):missing. 2022-03-21 17:58:20 +02:00
a.bouhuolia
90c77d80eb fix(ItemEntries): align checkbox. 2022-03-21 16:13:50 +02:00
a.bouhuolia
932afddf11 fix: remote line min lines. 2022-03-21 13:41:07 +02:00
a.bouhuolia
a533c3cb76 fix(Datatable): actions cell align center. 2022-03-21 13:27:59 +02:00
a.bouhuolia
2f36594459 fix(DataTable): cells type. 2022-03-21 13:15:10 +02:00
a.bouhuolia
a093c0d335 fix(PaymentMadeForm|PaymentReceiveForm): keep previous data of due invoices. 2022-03-20 20:54:07 +02:00
elforjani13
120f8d15ec feat: add warehouse transfer 2022-03-20 20:17:29 +02:00
elforjani13
65bb05d498 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-20 20:14:23 +02:00
elforjani13
64d73fa7b9 feat: add warehouse transfer & expenses & journal. 2022-03-20 20:13:49 +02:00
a.bouhuolia
928e903fe0 fix(WarehouseTransfer): set item cost to form entries. 2022-03-20 19:00:50 +02:00
elforjani13
23261e975d Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-20 17:58:15 +02:00
elforjani13
e51f203ca8 feat(purchases): add purchases. 2022-03-20 17:56:37 +02:00
a.bouhuolia
35f40503f3 feat(ExpenseForm): optimize style fo expense form. 2022-03-20 17:23:35 +02:00
a.bouhuolia
f86845ea91 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-20 16:45:24 +02:00
a.bouhuolia
29fbcf1f1c fix(WarehouseTransfer). 2022-03-20 16:43:49 +02:00
elforjani13
39a68f5c25 feat(Sales): add sales. 2022-03-20 16:16:22 +02:00
a.bouhuolia
89b28903fa fix: change the min lines of entries. 2022-03-20 12:21:16 +02:00
a.bouhuolia
4f7e9caedb Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-20 12:04:24 +02:00
a.bouhuolia
ef91afe041 feat(InvoiceFormat): invoice footer totals. 2022-03-20 12:04:17 +02:00
elforjani13
dd5e10ef83 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-03-20 11:21:59 +02:00
elforjani13
acdec70385 feat(S&P): Form Footer. 2022-03-20 11:20:13 +02:00
a.bouhuolia
05126253db fix(InvoiceForm): control display exchange rate input for foreign customers. 2022-03-20 11:03:48 +02:00
a.bouhuolia
cc637471d9 feat(ExchangeRateInput): optimize style. 2022-03-19 23:19:30 +02:00
a.bouhuolia
321d206670 feat(TotalLine): add extra border style. 2022-03-19 23:16:41 +02:00
a.bouhuolia
69c47aee4d feat(InvoiceForm): remove the entries table footer. 2022-03-19 23:15:37 +02:00
a.bouhuolia
ad149c1b18 feat(FormTopbar): optimize style. 2022-03-19 23:15:04 +02:00
a.bouhuolia
7df4cbdf54 fix(InvoiceFormHeader): remove terms select field. 2022-03-19 23:14:27 +02:00
a.bouhuolia
ca0672509b feat(InvoiceFormFooter): add invoice form footer the total lines. 2022-03-19 23:13:32 +02:00
a.bouhuolia
966d1100aa fix(CustomerDrawerLink): prevent the default JS behaivour. 2022-03-19 23:13:05 +02:00
a.bouhuolia
0e263437e1 feat(DatatableEditable): restyle datatable editable component. 2022-03-19 23:12:40 +02:00
a.bouhuolia
e1977dbe07 feat(FTextArea): add TextArea component binded with Formik. 2022-03-19 23:11:50 +02:00
a.bouhuolia
e6d7d6aa1c feat(ExchangeRateInput): depend on currency code instead of country code. 2022-03-19 23:11:30 +02:00
a.bouhuolia
8e7955bc7e feat(Paper): add Paper icon. 2022-03-19 23:08:41 +02:00
a.bouhuolia
379d033344 feat(Icons): rename icons from country code to currency code. 2022-03-19 23:08:12 +02:00
a.bouhuolia
378110f6b3 feat: update @blueprintjs-formik/core package. 2022-03-19 23:07:16 +02:00
elforjani13
888c3a11e0 feat: fix journal. 2022-03-17 17:31:40 +02:00
elforjani13
b0407168a0 feat(payment receive & made): handle error. 2022-03-17 14:34:24 +02:00
elforjani13
7f3a494c8d fix: branch & warehouse multi select. 2022-03-16 22:59:26 +02:00
elforjani13
d85133b35e feat: fix make journal. 2022-03-16 19:55:27 +02:00
elforjani13
a360f8a62b feat(warehouses&branches): empty status localizations. 2022-03-15 17:01:29 +02:00
elforjani13
a91f303111 feat(warehouses transfer): warehouse transfer auto-increment. 2022-03-15 13:46:27 +02:00
elforjani13
f45d5ecf42 feat: localization. 2022-03-15 13:17:12 +02:00
elforjani13
3d49ebd1e7 feat: fix localization. 2022-03-15 13:16:49 +02:00
elforjani13
f84023f399 fix: missaing 2022-03-14 16:57:49 +02:00
elforjani13
dd46180d87 feat: add localizations. 2022-03-14 15:14:19 +02:00
elforjani13
3e91b01b61 fix:localization. 2022-03-14 15:13:53 +02:00
elforjani13
bd3059ecd8 feat(branches & warehouses): handle errors. 2022-03-13 15:20:00 +02:00
elforjani13
0bbd31dcce feat(branches & warehouses): fix Context menu. 2022-03-13 14:30:52 +02:00
elforjani13
c5c490d7ce feat(expenses): add expense form top bar. 2022-03-13 13:15:04 +02:00
elforjani13
733f198dcb feat(expenses): add exchange rate to details. 2022-03-13 13:10:01 +02:00
elforjani13
c17234f245 feat(branches & warehouses): fix features hooks. 2022-03-13 13:09:07 +02:00
elforjani13
a2bf37d5cd feat(branch & warehouse): handle error. 2022-03-12 20:01:32 +02:00
elforjani13
a75451cee7 feat(branches): fix branches provider. 2022-03-10 17:42:31 +02:00
elforjani13
c1ad349f6b feat(customer & vendor): add branch. 2022-03-09 22:03:21 +02:00
elforjani13
37f8662cc5 feat(vendor): add vendor opening balance dialog. 2022-03-09 20:59:19 +02:00
elforjani13
c5e360ffa2 feat(customer): add customer opening balance dialog. 2022-03-09 20:49:57 +02:00
elforjani13
098429d31a feat(badDebt): fix currency code. 2022-03-09 20:48:47 +02:00
elforjani13
433b611188 feat(inventoryadjustment): add branch & warehouse. 2022-03-09 13:05:07 +02:00
elforjani13
6638accae6 feat(warehouses transfer): fix table state change. 2022-03-08 16:33:51 +02:00
elforjani13
2d34baa7a5 feat(branches & warehouses): fix api. 2022-03-08 15:47:28 +02:00
elforjani13
0f4176ae79 feat(exchangrate muted): fix style. 2022-03-08 12:05:37 +02:00
elforjani13
4f630d8365 feat(qucikpayment):fix currency code. 2022-03-08 12:05:30 +02:00
elforjani13
e38b96c528 feat(account): handle error. 2022-03-07 22:12:34 +02:00
elforjani13
e03dee2a9f feat(warehouse & Branch): handle error. 2022-03-07 21:53:54 +02:00
elforjani13
a8311f1798 feat(refund vendor):add exchange rate muted & branch. 2022-03-07 20:57:39 +02:00
elforjani13
b8b95c7929 feat(refund credit):add exchange rate muted & branch. 2022-03-07 20:57:20 +02:00
elforjani13
2501626d70 feat(qucikpayment):add exchange rate muted & branch. 2022-03-07 20:46:48 +02:00
elforjani13
87a56dcd95 feat(S&P): fix navigation bar if warehouses or branches feature. 2022-03-07 18:43:21 +02:00
elforjani13
b26b4c5491 feat(qucikpayment):add exchange rate muted. 2022-03-07 18:35:11 +02:00
elforjani13
d12e35f649 feat(cashflow): exchange rate muted. 2022-03-07 16:38:14 +02:00
elforjani13
51c7a0fcd8 feat(dashboard): add features api. 2022-03-07 00:18:58 +02:00
elforjani13
a639101e28 feat(cashflow): add exchange rate muted. 2022-03-06 23:26:09 +02:00
elforjani13
7467b63e54 feat(cashflow): add ExchangeRateMutedField. 2022-03-06 20:20:25 +02:00
elforjani13
5c52f80536 feat(branch & warehouse): fix EmptyStatus. 2022-03-06 15:11:04 +02:00
elforjani13
94c88a7003 feat(Bill): fix bill . 2022-03-03 19:12:22 +02:00
elforjani13
7f4ee26979 feat( S&P ): add branch name to details. 2022-03-02 19:07:09 +02:00
elforjani13
e46609e3f1 fix(invoice details): add branch name. 2022-03-02 16:56:41 +02:00
elforjani13
f814374279 feat(invoicedetail ): Add branch name to detial. 2022-03-02 14:23:28 +02:00
elforjani13
cfbc59280e feat( S&P ): Add currency code in conversion to invoice & credit. 2022-03-01 19:50:49 +02:00
elforjani13
0923c69c16 feat(Sales & Purchases ): add currency code in edit mode. 2022-03-01 15:57:47 +02:00
elforjani13
151e72a76d feat(Sales & Purchases ): add exchange rate in details. 2022-03-01 14:51:34 +02:00
elforjani13
ff2c74344a feat(OwnerContributionForm): add branch select. 2022-02-28 16:37:44 +02:00
elforjani13
eb340269c0 feat(Journal): add branch to topbar & entries columns. 2022-02-28 14:29:56 +02:00
elforjani13
cb9c7fcdb6 feat(OwnerContributionForm): add exchange rate. 2022-02-27 14:38:47 +02:00
elforjani13
31a5ee6dda feat(moneyIn): add exchange rate detail. 2022-02-27 14:26:10 +02:00
elforjani13
01db5a2faa feat(invoice detail): add exchange rate detail. 2022-02-27 14:23:57 +02:00
elforjani13
a3c79d98b0 feat(account): add currency select. 2022-02-27 14:10:22 +02:00
elforjani13
deddbea752 feat (warehouseTransfer): add status in details. 2022-02-23 19:47:30 +02:00
elforjani13
e0126018b8 feat (invoice detail): deatil exhange rate item. 2022-02-23 18:35:54 +02:00
elforjani13
22eb7a1cc1 feat(Sales & Purchases ): add currency in header & entries. 2022-02-23 14:47:12 +02:00
elforjani13
e6a7c7bc58 feat(Sales & Purchases ): add setfieldvalue exchange rate. 2022-02-23 12:22:27 +02:00
elforjani13
cf7d032aae feat(warehousetTransfer): fix warehouse alert. 2022-02-22 15:59:47 +02:00
elforjani13
faea111f46 feat(warehousetTransfer): add warehouse transfer views. 2022-02-22 15:56:30 +02:00
elforjani13
836be59cbf feat(warehousetTransfer): warehouse floating actions. 2022-02-22 15:47:42 +02:00
elforjani13
ffd6629b80 feat(warehousetTransfer ): add warehouse status. 2022-02-22 15:37:03 +02:00
elforjani13
9ff91e27e5 feat(Sales & Purchases ): add currency tag. 2022-02-21 19:30:00 +02:00
elforjani13
b15437c88e feat(manual journal): add exchange rate input. 2022-02-21 16:03:57 +02:00
elforjani13
7c9ad8438c feat(Sales & Purchases ): add exchange rate input. 2022-02-21 15:25:32 +02:00
a.bouhuolia
98a02396a9 Merge branch 'develop' into main 2022-02-21 15:02:35 +02:00
a.bouhuolia
c7673f57cd dump v1.6.3. 2022-02-21 15:02:08 +02:00
a.bouhuolia
aa39aab93a fix(Billing): display payment methods only if subscription is not active. 2022-02-21 14:56:55 +02:00
a.bouhuolia
8e6b0b496f fix: BIG-337 Display billing page once the organization subscription is inactive. 2022-02-21 14:38:41 +02:00
elforjani13
914e1de79f feat(Sales & Purchases ): add FormTopBar. 2022-02-20 22:31:52 +02:00
elforjani13
f6f949bcbc Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-02-20 18:56:09 +02:00
elforjani13
f7790ef440 fix(Branches): min height. 2022-02-20 18:49:18 +02:00
elforjani13
05b0f5caac fix(Branches & warehouses ): mark primary. 2022-02-20 18:38:19 +02:00
a.bouhuolia
f5983937b0 fix: warehouse transfer. 2022-02-20 17:45:50 +02:00
a.bouhuolia
3a4c1adbd4 Merge branch 'feature/multi-dimensions' of https://github.com/bigcapitalhq/client into feature/multi-dimensions 2022-02-20 17:08:36 +02:00
a.bouhuolia
e9d379c623 fix: organize the warehouses preferences. 2022-02-20 17:08:30 +02:00
elforjani13
b46c3f4843 feat(Sales & Purchases ): add branch & warehouse. 2022-02-20 13:54:31 +02:00
a.bouhuolia
96635ffa84 Merge branch 'develop' into main 2022-02-18 20:44:42 +02:00
a.bouhuolia
e874b89d2d fix: try to fix styled-components. 2022-02-18 20:32:21 +02:00
a.bouhuolia
60d37e3424 Revert "fix: try to comment FinancialSkeletonTable component."
This reverts commit e3f2c82a38.
2022-02-18 20:10:53 +02:00
a.bouhuolia
8ae39bf04c fix: styled-components components. 2022-02-18 19:52:37 +02:00
a.bouhuolia
e3f2c82a38 fix: try to comment FinancialSkeletonTable component. 2022-02-18 19:29:12 +02:00
a.bouhuolia
68c0678dc3 Merge branch 'develop' into main 2022-02-17 12:10:20 +02:00
a.bouhuolia
030be9652c feat: add BS and PL reports to page of financial reports list. 2022-02-17 11:40:40 +02:00
a.bouhuolia
554527f17d fix(VendorTransaction): column accessor/id. 2022-02-16 18:47:36 +02:00
a.bouhuolia
79144ad4a5 fix: re-structure the system tables reports. 2022-02-16 18:44:10 +02:00
a.bouhuolia
e6fcbfeea6 fix: control report drawer header. 2022-02-16 17:49:28 +02:00
a.bouhuolia
7eacaa0660 fix: financial report data tables. 2022-02-14 14:09:17 +02:00
a.bouhuolia
673808cceb feat: add sticky table head to specific item transactions table. 2022-02-13 17:22:29 +02:00
a.bouhuolia
f27ef2c9b0 fix: style of vendor/customer balance summary. 2022-02-13 17:17:09 +02:00
a.bouhuolia
da699a766a Merge branch 'develop' into main 2022-01-13 15:40:55 +02:00
a.bouhuolia
f1899e1ce1 Merge branch 'develop' into main 2022-01-08 18:20:08 +02:00
Ahmed Bouhuolia
11851d114d Merge pull request #16 from bigcapitalhq/develop
Release 1.5.5
2022-01-04 22:35:49 +02:00
a.bouhuolia
21779007be fix: application version. 2022-01-03 23:14:11 +02:00
a.bouhuolia
4fc1ecdc2d Merge branch 'main' of https://github.com/bigcapitalhq/client into main 2022-01-03 19:42:48 +02:00
a.bouhuolia
c9b5cecf7a Merge branch 'develop' into main 2022-01-03 19:42:23 +02:00
elforjani13
c31e9dcd29 fix: inventory adjustment & contacts drawer. 2022-01-03 14:35:50 +02:00
elforjani13
430ab95dc3 landed cost localiztion. 2022-01-03 13:38:22 +02:00
Ahmed Bouhuolia
8100a57195 Merge pull request #15 from bigcapitalhq/develop
Merge `develop` to `main`
2022-01-03 12:31:14 +02:00
495 changed files with 10665 additions and 2632 deletions

View File

@@ -2,6 +2,73 @@
All notable changes to Bigcapital server-side will be in this file. All notable changes to Bigcapital server-side will be in this file.
## [1.7.2-rc.2] - 04-04-2022
### Fixed
- Add the missing Arabic localization.
- Subscription plans modifications.
## [1.7.1-rc.2] - 30-03-2022
## Added
- `BIG-141` Add inactive status to item drawer details.
- `BIG-278` Add created at date on expense details.
- `BIG-350` Add empty status content of warehouse transfers service.
- `BIG-344` Add branch details to manual journal and expense details.
## Fixed
- `BIG-221` Remove Non-inventory radio choice on item form.
- `BIG-236` Validate estimate expiration date should be equal or bigger than estimate date.
- `BIG-237` Validate invoice due date should be equal or bigger than invoice date.
- `BIG-238` Validate bill due date should be equal or bigger than bill date.
- `BIG-280` Optimize style of multi-select accounts menu.
- `BIG-284` Cashflow statement loading bar.
- `BIG-296` Creating a new child account from accounts list.
- `BIG-301` Navigation bar divider on actions bar hide with permissions control.
- `BIG-304` Adding cash or bank account from cash flow service.
- `BIG-351` Invalid date in the inventory adjustment detail.
- `BIG-352` Fix terms and notes fields on footer of all services.
- `BIG-354` Validate the warehouse transfer quantity should be above zero.
## [1.7.0-rc.1] - 24-03-2022
## Added
- Multiply currencies with foreign currencies.
- Multiply warehouses to track inventory items.
- Multiply branches to track organization transactions.
- Transfer orders between warehouses.
- Integrate financial reports with multiply branches.
- Integrate inventory reports with multiply warehouses.
## Changes
- Optimize style of sale invoice form.
- Optimize style of sale receipt form.
- Optimize style of credit note form.
- Optimize style of payment receive form.
- Optimize style of bill form.
- Optimize style of payment made form.
- Optimize style of manual journal form.
- Optimize style of expense form.
## [1.6.3] - 21-02-2022
### Fixed
- `BIG-337` Display billing page once the organization subscription is inactive.
## [1.6.2] - 19-02-2022
### Fixed
- fix syled components dependency with imported as default components.
## [1.6.0] - 18-02-2022
### Added
- Balance sheet comparison of previous period (PP).
- Balance sheet comparison of previous year (PY).
- Balance sheet percentage analysis columns and rows basis.
- Profit & loss sheet comparison of preivous period (PP).
- Profit & loss sheet comparison of previous year (PY).
- Profit & loss sheet percentage analysis columns, rows, income and expenses basis.
## [1.5.8] - 13-01-2022 ## [1.5.8] - 13-01-2022
### Added ### Added

View File

@@ -85,6 +85,9 @@ function getClientEnvironment(publicUrl) {
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
// Application version.
VERSION: paths.appVersion
} }
); );
// Stringify all values so we can feed into webpack DefinePlugin // Stringify all values so we can feed into webpack DefinePlugin

View File

@@ -48,6 +48,8 @@ const resolveModule = (resolveFn, filePath) => {
return resolveFn(`${filePath}.js`); return resolveFn(`${filePath}.js`);
}; };
const appVersion = require(resolveApp('package.json')).version;
// config after eject: we're in ./config/ // config after eject: we're in ./config/
module.exports = { module.exports = {
dotenv: resolveApp('.env'), dotenv: resolveApp('.env'),
@@ -65,6 +67,7 @@ module.exports = {
proxySetup: resolveApp('src/setupProxy.js'), proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'), appNodeModules: resolveApp('node_modules'),
publicUrlOrPath, publicUrlOrPath,
appVersion
}; };

View File

@@ -1,10 +1,10 @@
{ {
"name": "bigcapital-client", "name": "bigcapital-client",
"version": "1.5.8", "version": "1.7.1",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@babel/core": "7.8.4", "@babel/core": "7.8.4",
"@blueprintjs-formik/core": "^0.1.5", "@blueprintjs-formik/core": "^0.2.1",
"@blueprintjs-formik/select": "^0.1.4", "@blueprintjs-formik/select": "^0.1.4",
"@blueprintjs/core": "^3.50.2", "@blueprintjs/core": "^3.50.2",
"@blueprintjs/datetime": "^3.23.12", "@blueprintjs/datetime": "^3.23.12",

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -221,3 +221,5 @@ export const ACCOUNT_TYPES = [
incomeSheet: true, incomeSheet: true,
}, },
]; ];
export const FOREIGN_CURRENCY_ACCOUNTS = ['cash', 'bank'];

7
src/common/cellTypes.js Normal file
View File

@@ -0,0 +1,7 @@
export const CellType = {
Text: 'text',
Field: 'field',
Button: 'button'
}

View File

@@ -2,5 +2,6 @@
export const Features = { export const Features = {
Warehouses: 'warehouses', Warehouses: 'warehouses',
Branches: 'branches' Branches: 'branches',
ManualJournal: 'manualJournal',
} }

View File

@@ -1,4 +1,6 @@
export * from './accountTypes';
export * from './TableStyle'; export * from './TableStyle';
export * from './features'; export * from './features';
export * from './cellTypes';
export const Align = { Left: 'left', Right: 'right', Center: 'center' }; export const Align = { Left: 'left', Right: 'right', Center: 'center' };

View File

@@ -0,0 +1,73 @@
import React from 'react';
import styled from 'styled-components';
import { MenuItem } from '@blueprintjs/core';
import { FMultiSelect } from '../Forms';
import classNames from 'classnames';
import { Classes } from '@blueprintjs/popover2';
/**
*
* @param {*} query
* @param {*} account
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const accountItemPredicate = (query, account, _index, exactMatch) => {
const normalizedTitle = account.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${account.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
*
* @param {*} account
* @param {*} param1
* @returns
*/
const accountItemRenderer = (
account,
{ handleClick, modifiers, query },
{ isSelected },
) => {
return (
<MenuItem
icon={isSelected ? 'tick' : 'blank'}
text={account.name}
label={account.code}
key={account.id}
onClick={handleClick}
/>
);
};
const accountSelectProps = {
itemPredicate: accountItemPredicate,
itemRenderer: accountItemRenderer,
valueAccessor: (item) => item.id,
labelAccessor: (item) => item.code,
tagRenderer: (item) => item.name,
};
/**
* branches mulit select.
* @param {*} param0
* @returns {JSX.Element}
*/
export function AccountMultiSelect({ accounts, ...rest }) {
return (
<FMultiSelect
items={accounts}
popoverProps={{
minimal: true,
}}
{...accountSelectProps}
{...rest}
/>
);
}

View File

@@ -0,0 +1 @@
export * from './AccountMultiSelect';

View File

@@ -0,0 +1,124 @@
import React from 'react';
import intl from 'react-intl-universal';
import { MenuItem } from '@blueprintjs/core';
import { Suggest } from '@blueprintjs/select';
import { FormattedMessage as T } from 'components';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
/**
* branch suggest field.
* @returns
*/
export default function BranchSuggestField({
branches,
initialBranchId,
selectedBranchId,
defaultSelectText = intl.get('select_branch'),
popoverFill = false,
onBranchSelected,
...suggestProps
}) {
const initialBranch = React.useMemo(
() => branches.find((b) => b.id === initialBranchId),
[initialBranchId, branches],
);
const [selectedBranch, setSelectedBranch] = React.useState(
initialBranch || null,
);
React.useEffect(() => {
if (typeof selectedBranchId !== 'undefined') {
const branch = selectedBranchId
? branches.find((a) => a.id === selectedBranchId)
: null;
setSelectedBranch(branch);
}
}, [selectedBranchId, branches, setSelectedBranch]);
/**
*
* @param {*} branch
* @returns
*/
const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
return (
<MenuItem
// active={modifiers.active}
disabled={modifiers.disabled}
label={branch.code}
key={branch.id}
onClick={handleClick}
text={branch.name}
/>
);
};
/**
*
* @param {*} query
* @param {*} branch
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const branchItemPredicate = (query, branch, _index, exactMatch) => {
const normalizedTitle = branch.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${branch.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
*
* @param {*} branch
* @returns
*/
const brnachItemSelect = React.useCallback(
(branch) => {
if (branch.id) {
setSelectedBranch({ ...branch });
onBranchSelected && onBranchSelected(branch);
}
},
[setSelectedBranch, onBranchSelected],
);
/**
*
* @param {*} inputVaue
* @returns
*/
const branchInputValueRenderer = (inputValue) => {
if (inputValue) {
return inputValue.name.toString();
}
return '';
};
return (
<Suggest
items={branches}
noResults={<MenuItem disabled={true} text={<T id={'no_accounts'} />} />}
itemRenderer={branchItemRenderer}
itemPredicate={branchItemPredicate}
onItemSelect={brnachItemSelect}
selectedItem={selectedBranch}
inputProps={{ placeholder: defaultSelectText }}
resetOnClose={true}
fill={true}
popoverProps={{ minimal: true, boundary: 'window' }}
inputValueRenderer={branchInputValueRenderer}
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
{...suggestProps}
/>
);
}

View File

@@ -38,8 +38,8 @@ const branchItemRenderer = (
active={modifiers.active} active={modifiers.active}
disabled={modifiers.disabled} disabled={modifiers.disabled}
icon={isSelected ? 'tick' : 'blank'} icon={isSelected ? 'tick' : 'blank'}
text={branch.name.toString()} text={branch.name}
label={branch.code.toString()} label={branch.code}
key={branch.id} key={branch.id}
onClick={handleClick} onClick={handleClick}
/> />
@@ -50,14 +50,14 @@ const branchSelectProps = {
itemPredicate: branchItemPredicate, itemPredicate: branchItemPredicate,
itemRenderer: branchItemRenderer, itemRenderer: branchItemRenderer,
valueAccessor: (item) => item.id, valueAccessor: (item) => item.id,
labelAccessor: (item) => item.label, labelAccessor: (item) => item.code,
tagRenderer: (item) => item.name, tagRenderer: (item) => item.name,
}; };
/** /**
* branches mulit select. * branches mulit select.
* @param {*} param0 * @param {*} param0
* @returns * @returns {JSX.Element}
*/ */
export function BranchMultiSelect({ branches, ...rest }) { export function BranchMultiSelect({ branches, ...rest }) {
return ( return (

View File

@@ -35,7 +35,7 @@ const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
<MenuItem <MenuItem
active={modifiers.active} active={modifiers.active}
disabled={modifiers.disabled} disabled={modifiers.disabled}
label={branch.name.toString()} label={branch.code}
key={branch.id} key={branch.id}
onClick={handleClick} onClick={handleClick}
text={text} text={text}

View File

@@ -1,3 +1 @@
export * from './ButtonLink'; export * from './ButtonLink';

View File

@@ -0,0 +1,10 @@
import React from 'react';
import { CurrencyTag } from 'components';
/**
* base currecncy.
* @returns
*/
export function BaseCurrency({ currency }) {
return <CurrencyTag>{currency}</CurrencyTag>;
}

View File

@@ -1 +1,2 @@
export * from './CurrencySelect' export * from './CurrencySelect';
export * from './BaseCurrency';

View File

@@ -1,23 +1,29 @@
import React from 'react'; import React from 'react';
import * as R from 'ramda'; import * as R from 'ramda';
import { ButtonLink } from 'components'; import { ButtonLink } from '../Button';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
function CustomerDrawerLinkComponent({ function CustomerDrawerLinkComponent({
// #ownProps // #ownProps
children, children,
customerId, customerId,
className,
// #withDrawerActions // #withDrawerActions
openDrawer, openDrawer,
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleCustomerDrawer = () => { const handleCustomerDrawer = (event) => {
openDrawer('customer-details-drawer', { customerId }); openDrawer('customer-details-drawer', { customerId });
event.preventDefault();
}; };
return <ButtonLink onClick={handleCustomerDrawer}>{children}</ButtonLink>; return (
<ButtonLink className={className} onClick={handleCustomerDrawer}>
{children}
</ButtonLink>
);
} }
export const CustomerDrawerLink = R.compose(withDrawerActions)( export const CustomerDrawerLink = R.compose(withDrawerActions)(

View File

@@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { Ability } from '@casl/ability'; import { Ability } from '@casl/ability';
import { createContextualCan } from '@casl/react'; import { createContextualCan } from '@casl/react';
import { useDashboardMeta } from '../../hooks/query';
import { useDashboardMetaBoot } from './DashboardBoot';
export const AbilityContext = React.createContext(); export const AbilityContext = React.createContext();
export const Can = createContextualCan(AbilityContext.Consumer); export const Can = createContextualCan(AbilityContext.Consumer);
@@ -11,8 +12,8 @@ export const Can = createContextualCan(AbilityContext.Consumer);
*/ */
export function DashboardAbilityProvider({ children }) { export function DashboardAbilityProvider({ children }) {
const { const {
data: { abilities }, meta: { abilities },
} = useDashboardMeta(); } = useDashboardMetaBoot();
// Ability instance. // Ability instance.
const ability = new Ability(abilities); const ability = new Ability(abilities);

View File

@@ -6,18 +6,26 @@ import {
} from '../../hooks/query'; } from '../../hooks/query';
import { useSplashLoading } from '../../hooks/state'; import { useSplashLoading } from '../../hooks/state';
import { useWatch, useWatchImmediate, useWhen } from '../../hooks'; import { useWatch, useWatchImmediate, useWhen } from '../../hooks';
import { useSubscription } from '../../hooks/state';
import { setCookie, getCookie } from '../../utils'; import { setCookie, getCookie } from '../../utils';
/** /**
* Dashboard meta async booting. * Dashboard meta async booting.
* - Fetches the dashboard meta only if the organization subscribe is active.
* - Once the dashboard meta query is loading display dashboard splash screen.
*/ */
export function useDashboardMetaBoot() { export function useDashboardMetaBoot() {
const { isSubscriptionActive } = useSubscription();
const { const {
data: dashboardMeta, data: dashboardMeta,
isLoading: isDashboardMetaLoading, isLoading: isDashboardMetaLoading,
isSuccess: isDashboardMetaSuccess, isSuccess: isDashboardMetaSuccess,
} = useDashboardMeta({ } = useDashboardMeta({
keepPreviousData: true, keepPreviousData: true,
// Avoid run the query if the organization subscription is not active.
enabled: isSubscriptionActive,
}); });
const [startLoading, stopLoading] = useSplashLoading(); const [startLoading, stopLoading] = useSplashLoading();
@@ -30,20 +38,12 @@ export function useDashboardMetaBoot() {
}, isDashboardMetaSuccess); }, isDashboardMetaSuccess);
return { return {
meta: dashboardMeta,
isLoading: isDashboardMetaLoading, isLoading: isDashboardMetaLoading,
isSuccess: isDashboardMetaSuccess
}; };
} }
/**
* Dashboard async booting.
* @returns {{ isLoading: boolean }}
*/
export function useDashboardBoot() {
const { isLoading } = useDashboardMetaBoot();
return { isLoading };
}
/** /**
* Application async booting. * Application async booting.
*/ */

View File

@@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { DashboardAbilityProvider } from '../../components'; import { DashboardAbilityProvider } from '../../components';
import { useDashboardBoot } from './DashboardBoot'; import { useDashboardMetaBoot } from './DashboardBoot';
/** /**
* Dashboard provider. * Dashboard provider.
*/ */
export default function DashboardProvider({ children }) { export default function DashboardProvider({ children }) {
const { isLoading } = useDashboardBoot(); const { isLoading } = useDashboardMetaBoot();
// Avoid display any dashboard component before complete booting. // Avoid display any dashboard component before complete booting.
if (isLoading) { if (isLoading) {

View File

@@ -1,13 +1,12 @@
import React, { useRef, useCallback, useMemo } from 'react'; import React, { useRef, useCallback, useMemo } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useCellAutoFocus } from 'hooks'; import { FormGroup, Classes, Intent } from '@blueprintjs/core';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { CellType } from 'common';
import { useCellAutoFocus } from 'hooks';
import AccountsSuggestField from 'components/AccountsSuggestField'; import AccountsSuggestField from 'components/AccountsSuggestField';
// import AccountsSelectList from 'components/AccountsSelectList';
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
/** /**
* Account cell renderer. * Account cell renderer.
*/ */
@@ -74,3 +73,4 @@ export default function AccountCellRenderer({
</FormGroup> </FormGroup>
); );
} }
AccountCellRenderer.cellType = CellType.Field;

View File

@@ -0,0 +1,44 @@
import React from 'react';
import { FormGroup, Intent, Classes } from '@blueprintjs/core';
import classNames from 'classnames';
import { CellType } from 'common';
import BranchSuggestField from '../BranchSuggestField';
/**
* Branches list field cell.
* @returns
*/
export default function BranchesListFieldCell({
column: { id },
row: { index, original },
payload: { branches, updateData, errors },
}) {
const handleBranchSelected = React.useCallback(
(branch) => {
updateData(index, 'branch_id', branch.id);
},
[updateData, index],
);
const error = errors?.[index]?.[id];
return (
<FormGroup
intent={error ? Intent.DANGER : null}
className={classNames(
'form-group--select-list',
'form-group--contacts-list',
Classes.FILL,
)}
>
<BranchSuggestField
branches={branches}
onBranchSelected={handleBranchSelected}
selectedBranchId={original?.branch_id}
/>
</FormGroup>
);
}
BranchesListFieldCell.cellType = CellType.Field;

View File

@@ -2,6 +2,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { Classes, Checkbox, FormGroup, Intent } from '@blueprintjs/core'; import { Classes, Checkbox, FormGroup, Intent } from '@blueprintjs/core';
import { CellType } from 'common';
const CheckboxEditableCell = ({ const CheckboxEditableCell = ({
row: { index, original }, row: { index, original },
@@ -45,4 +46,6 @@ const CheckboxEditableCell = ({
); );
}; };
CheckboxEditableCell.cellType = CellType.Field;
export default CheckboxEditableCell; export default CheckboxEditableCell;

View File

@@ -1,9 +1,9 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { FormGroup, Intent, Classes } from '@blueprintjs/core'; import { FormGroup, Intent, Classes } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { ContactSelecetList } from 'components';
import ContactsSuggestField from 'components/ContactsSuggestField';
import { CellType } from 'common';
import ContactsSuggestField from 'components/ContactsSuggestField';
export default function ContactsListCellRenderer({ export default function ContactsListCellRenderer({
column: { id }, column: { id },
row: { index, original }, row: { index, original },
@@ -37,3 +37,5 @@ export default function ContactsListCellRenderer({
</FormGroup> </FormGroup>
); );
} }
ContactsListCellRenderer.cellType = CellType.Field;

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Classes, InputGroup, FormGroup, Intent } from '@blueprintjs/core'; import { Classes, InputGroup, FormGroup, Intent } from '@blueprintjs/core';
import { CellType } from 'common';
const InputEditableCell = ({ const InputEditableCell = ({
row: { index }, row: { index },
@@ -37,4 +38,6 @@ const InputEditableCell = ({
); );
}; };
InputEditableCell.cellType = CellType.Field;
export default InputEditableCell; export default InputEditableCell;

View File

@@ -3,6 +3,7 @@ import classNames from 'classnames';
import { FormGroup, Classes, Intent } from '@blueprintjs/core'; import { FormGroup, Classes, Intent } from '@blueprintjs/core';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { CellType } from 'common';
import ItemsSuggestField from 'components/ItemsSuggestField'; import ItemsSuggestField from 'components/ItemsSuggestField';
import { useCellAutoFocus } from 'hooks'; import { useCellAutoFocus } from 'hooks';
@@ -54,3 +55,5 @@ export default function ItemsListCell({
</FormGroup> </FormGroup>
); );
} }
ItemsListCell.cellType = CellType.Field;

View File

@@ -1,7 +1,9 @@
import React, { useCallback, useState, useEffect } from 'react'; import React, { useCallback, useState, useEffect } from 'react';
import { FormGroup, Intent } from '@blueprintjs/core'; import { FormGroup, Intent } from '@blueprintjs/core';
import { MoneyInputGroup } from 'components'; import { MoneyInputGroup } from 'components';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import { CellType } from 'common';
// Input form cell renderer. // Input form cell renderer.
const MoneyFieldCellRenderer = ({ const MoneyFieldCellRenderer = ({
@@ -48,4 +50,6 @@ const MoneyFieldCellRenderer = ({
); );
}; };
MoneyFieldCellRenderer.cellType = CellType.Field;
export default MoneyFieldCellRenderer; export default MoneyFieldCellRenderer;

View File

@@ -1,6 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { FormGroup, NumericInput, Intent } from '@blueprintjs/core'; import { FormGroup, NumericInput, Intent } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { CellType } from 'common';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
/** /**
@@ -36,8 +38,10 @@ export default function NumericInputCell({
onValueChange={handleValueChange} onValueChange={handleValueChange}
onBlur={onBlur} onBlur={onBlur}
fill={true} fill={true}
buttonPosition={"none"} buttonPosition={'none'}
/> />
</FormGroup> </FormGroup>
); );
} }
NumericInputCell.cellType = CellType.Field;

View File

@@ -1,8 +1,9 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import PaymentReceiveListField from 'components/PaymentReceiveListField';
import classNames from 'classnames'; import classNames from 'classnames';
import { FormGroup, Classes, Intent } from '@blueprintjs/core'; import { FormGroup, Classes, Intent } from '@blueprintjs/core';
import PaymentReceiveListField from 'components/PaymentReceiveListField';
import { CellType } from 'common';
function PaymentReceiveListFieldCell({ function PaymentReceiveListFieldCell({
column: { id }, column: { id },
row: { index }, row: { index },
@@ -32,4 +33,6 @@ function PaymentReceiveListFieldCell({
); );
} }
PaymentReceiveListFieldCell.cellType = CellType.Field;
export default PaymentReceiveListFieldCell; export default PaymentReceiveListFieldCell;

View File

@@ -1,6 +1,8 @@
import React, { useCallback, useState, useEffect } from 'react'; import React, { useCallback, useState, useEffect } from 'react';
import { FormGroup, Intent } from '@blueprintjs/core'; import { FormGroup, Intent } from '@blueprintjs/core';
import { MoneyInputGroup } from 'components'; import { MoneyInputGroup } from 'components';
import { CellType } from 'common';
const PercentFieldCell = ({ const PercentFieldCell = ({
cell: { value: initialValue }, cell: { value: initialValue },
@@ -38,4 +40,6 @@ const PercentFieldCell = ({
); );
}; };
PercentFieldCell.cellType = CellType.Field;
export default PercentFieldCell; export default PercentFieldCell;

View File

@@ -2,6 +2,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Classes, Switch, FormGroup, Intent } from '@blueprintjs/core'; import { Classes, Switch, FormGroup, Intent } from '@blueprintjs/core';
import { CellType } from 'common';
import { safeInvoke } from 'utils'; import { safeInvoke } from 'utils';
/** /**
@@ -48,4 +49,6 @@ const SwitchEditableCell = ({
); );
}; };
SwitchEditableCell.cellType = CellType.Field;
export default SwitchEditableCell; export default SwitchEditableCell;

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Classes, TextArea, FormGroup, Intent } from '@blueprintjs/core'; import { Classes, TextArea, FormGroup, Intent } from '@blueprintjs/core';
import { CellType } from 'common';
const TextAreaEditableCell = ({ const TextAreaEditableCell = ({
row: { index }, row: { index },
@@ -39,4 +40,6 @@ const TextAreaEditableCell = ({
); );
}; };
TextAreaEditableCell.cellType = CellType.Field;
export default TextAreaEditableCell; export default TextAreaEditableCell;

View File

@@ -9,6 +9,7 @@ import NumericInputCell from './NumericInputCell';
import CheckBoxFieldCell from './CheckBoxFieldCell'; import CheckBoxFieldCell from './CheckBoxFieldCell';
import SwitchFieldCell from './SwitchFieldCell'; import SwitchFieldCell from './SwitchFieldCell';
import TextAreaCell from './TextAreaCell'; import TextAreaCell from './TextAreaCell';
import BranchesListFieldCell from './BranchesListFieldCell';
export { export {
AccountsListFieldCell, AccountsListFieldCell,
@@ -23,4 +24,5 @@ export {
CheckBoxFieldCell, CheckBoxFieldCell,
SwitchFieldCell, SwitchFieldCell,
TextAreaCell, TextAreaCell,
BranchesListFieldCell,
}; };

View File

@@ -1,8 +1,7 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import styled from 'styled-components';
import { CLASSES } from 'common/classes';
import { DataTable, If } from 'components'; import { DataTable } from 'components';
import 'style/components/DataTable/DataTableEditable.scss';
/** /**
* Editable datatable. * Editable datatable.
@@ -11,26 +10,106 @@ export default function DatatableEditable({
totalRow = false, totalRow = false,
actions, actions,
name, name,
className,
...tableProps ...tableProps
}) { }) {
return ( return (
<div <DatatableEditableRoot>
className={classNames(
CLASSES.DATATABLE_EDITOR,
{
[`${CLASSES.DATATABLE_EDITOR}--${name}`]: name,
},
className,
)}
>
<DataTable {...tableProps} /> <DataTable {...tableProps} />
</DatatableEditableRoot>
<If condition={actions}>
<div className={classNames(CLASSES.DATATABLE_EDITOR_ACTIONS)}>
{actions}
</div>
</If>
</div>
); );
} }
const DatatableEditableRoot = styled.div`
.bp3-form-group {
margin-bottom: 0;
}
.table {
border: 1px solid #d2dce2;
border-radius: 5px;
background-color: #fff;
.th,
.td {
border-left: 1px solid #e2e2e2;
&:first-of-type{
border-left: 0;
}
}
.thead {
.tr .th {
padding: 9px 14px;
background-color: #f2f3fb;
font-size: 13px;
color: #415060;
border-bottom: 1px solid #d2dce2;
&,
.inner-resizer {
border-left-color: transparent;
}
}
}
.tbody {
.tr .td {
border-bottom: 0;
border-bottom: 1px solid #d8d8d8;
min-height: 38px;
padding: 4px 14px;
&.td-field-type,
&.td-button-type{
padding: 2px;
}
}
.tr:last-of-type .td {
border-bottom: 0;
}
.tr {
&:hover .td,
.bp3-input {
background-color: transparent;
}
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
.form-group--select-list .bp3-button {
border-color: #ffffff;
color: #222;
border-radius: 3px;
text-align: inherit;
}
.bp3-form-group:not(.bp3-intent-danger) .bp3-input {
border-radius: 2px;
padding-left: 14px;
padding-right: 14px;
&:focus {
box-shadow: 0 0 0 2px #116cd0;
}
}
.form-group--select-list .bp3-button {
padding-left: 6px;
padding-right: 6px;
&:after {
display: none;
}
}
.form-group--select-list,
.bp3-form-group {
&.bp3-intent-danger {
.bp3-button:not(.bp3-minimal),
.bp3-input {
border-color: #f7b6b6;
}
}
}
.td.actions {
.bp3-button {
color: #80858f;
}
}
}
}
}
`;

View File

@@ -1,7 +1,8 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { If } from 'components'; import { camelCase} from 'lodash';
import { Skeleton } from 'components';
import { If, Skeleton } from 'components';
import { useAppIntlContext } from 'components/AppIntlProvider'; import { useAppIntlContext } from 'components/AppIntlProvider';
import TableContext from './TableContext'; import TableContext from './TableContext';
import { saveInvoke, ignoreEventFromSelectors } from 'utils'; import { saveInvoke, ignoreEventFromSelectors } from 'utils';
@@ -57,6 +58,7 @@ export default function TableCell({ cell, row, index }) {
} }
saveInvoke(onCellClick, cell, event); saveInvoke(onCellClick, cell, event);
}; };
const cellType = camelCase(cell.column.Cell.cellType) || 'text';
return ( return (
<div <div
@@ -65,6 +67,9 @@ export default function TableCell({ cell, row, index }) {
'is-text-overview': cell.column.textOverview, 'is-text-overview': cell.column.textOverview,
clickable: cell.column.clickable, clickable: cell.column.clickable,
'align-right': cell.column.align === 'right', 'align-right': cell.column.align === 'right',
'align-center': cell.column.align === 'center',
[`td-${cell.column.id}`]: cell.column.id,
[`td-${cellType}-type`]: !!cellType,
}), }),
onClick: handleCellClick, onClick: handleCellClick,
})} })}

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Checkbox } from '@blueprintjs/core'; import { Checkbox } from '@blueprintjs/core';
import { CellType } from 'common';
export default function TableIndeterminateCheckboxRow({ row }) { export default function TableIndeterminateCheckboxRow({ row }) {
return ( return (
<div class="selection-checkbox"> <div class="selection-checkbox">
@@ -8,3 +8,5 @@ export default function TableIndeterminateCheckboxRow({ row }) {
</div> </div>
); );
} }
TableIndeterminateCheckboxRow.cellType = CellType.Field;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { DetailItem } from 'components';
import { isEqual } from 'lodash';
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
/**
* Detail exchange rate item.
* @param {*} param0
* @param {*} param1
* @returns
*/
function DetailExchangeRate({
exchangeRate,
toCurrency,
// #withCurrentOrganization
organization: { base_currency },
}) {
if (isEqual(base_currency, toCurrency)) {
return null;
}
return (
<DetailItem label={intl.get('exchange_rate')}>
1 {base_currency} = {exchangeRate} {toCurrency}
</DetailItem>
);
}
export const ExchangeRateDetailItem = R.compose(withCurrentOrganization())(
DetailExchangeRate,
);

View File

@@ -38,6 +38,8 @@ import WarehouseFormDialog from '../containers/Dialogs/WarehouseFormDialog';
import BranchFormDialog from '../containers/Dialogs/BranchFormDialog'; import BranchFormDialog from '../containers/Dialogs/BranchFormDialog';
import BranchActivateDialog from '../containers/Dialogs/BranchActivateDialog'; import BranchActivateDialog from '../containers/Dialogs/BranchActivateDialog';
import WarehouseActivateDialog from '../containers/Dialogs/WarehouseActivateDialog'; import WarehouseActivateDialog from '../containers/Dialogs/WarehouseActivateDialog';
import CustomerOpeningBalanceDialog from '../containers/Dialogs/CustomerOpeningBalanceDialog';
import VendorOpeningBalanceDialog from '../containers/Dialogs/VendorOpeningBalanceDialog';
/** /**
* Dialogs container. * Dialogs container.
@@ -86,6 +88,8 @@ export default function DialogsContainer() {
<BranchFormDialog dialogName={'branch-form'} /> <BranchFormDialog dialogName={'branch-form'} />
<BranchActivateDialog dialogName={'branch-activate'} /> <BranchActivateDialog dialogName={'branch-activate'} />
<WarehouseActivateDialog dialogName={'warehouse-activate'} /> <WarehouseActivateDialog dialogName={'warehouse-activate'} />
<CustomerOpeningBalanceDialog dialogName={'customer-opening-balance'} />
<VendorOpeningBalanceDialog dialogName={'vendor-opening-balance'} />
</div> </div>
); );
} }

View File

@@ -4,6 +4,7 @@ import { Classes, Icon, H4, Button } from '@blueprintjs/core';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
import styled from 'styled-components';
import { compose } from 'utils'; import { compose } from 'utils';
/** /**
@@ -13,6 +14,7 @@ function DrawerHeaderContent(props) {
const { const {
icon, icon,
title = <T id={'view_paper'} />, title = <T id={'view_paper'} />,
subTitle,
onClose, onClose,
name, name,
closeDrawer, closeDrawer,
@@ -30,7 +32,10 @@ function DrawerHeaderContent(props) {
return ( return (
<div className={Classes.DRAWER_HEADER}> <div className={Classes.DRAWER_HEADER}>
<Icon icon={icon} iconSize={Icon.SIZE_LARGE} /> <Icon icon={icon} iconSize={Icon.SIZE_LARGE} />
<H4>{title}</H4> <H4>
{title}
<SubTitle>{subTitle}</SubTitle>
</H4>
<Button <Button
aria-label="Close" aria-label="Close"
@@ -44,3 +49,24 @@ function DrawerHeaderContent(props) {
} }
export default compose(withDrawerActions)(DrawerHeaderContent); export default compose(withDrawerActions)(DrawerHeaderContent);
/**
* SubTitle Drawer header.
* @returns {React.JSX}
*/
function SubTitle({ children }) {
if (children == null) {
return null;
}
return <SubTitleHead>{children}</SubTitleHead>;
}
const SubTitleHead = styled.div`
color: #666;
font-size: 12px;
font-weight: 400;
line-height: 1;
padding: 2px 0px;
margin: 2px 0px;
`;

View File

@@ -12,23 +12,20 @@ export function ExchangeRateInputGroup({
formGroupProps, formGroupProps,
name, name,
}) { }) {
const fromCountryCode = 'US';
const toCountryCode = 'LY';
return ( return (
<FFormGroup inline={true} {...formGroupProps} name={name}> <FFormGroup inline={true} {...formGroupProps} name={name}>
<ControlGroup> <ControlGroup>
<ExchangeRatePrepend> <ExchangeRatePrepend>
<ExchangeFlagIcon countryCode={fromCountryCode} /> 1 {fromCurrency} = <ExchangeFlagIcon currencyCode={fromCurrency} /> 1 {fromCurrency} =
</ExchangeRatePrepend> </ExchangeRatePrepend>
<ExchangeRateField <ExchangeRateField
allowDecimals={false} allowDecimals={true}
allowNegativeValue={true} allowNegativeValue={true}
{...inputGroupProps} {...inputGroupProps}
name={name} name={name}
/> />
<ExchangeRateAppend> <ExchangeRateAppend>
<ExchangeFlagIcon countryCode={toCountryCode} /> {toCurrency} <ExchangeFlagIcon currencyCode={toCurrency} /> {toCurrency}
</ExchangeRateAppend> </ExchangeRateAppend>
</ControlGroup> </ControlGroup>
</FFormGroup> </FFormGroup>
@@ -36,7 +33,7 @@ export function ExchangeRateInputGroup({
} }
const ExchangeRateField = styled(FMoneyInputGroup)` const ExchangeRateField = styled(FMoneyInputGroup)`
max-width: 88px; max-width: 75px;
`; `;
const ExchangeRateSideIcon = styled.div` const ExchangeRateSideIcon = styled.div`

View File

@@ -0,0 +1,94 @@
import React from 'react';
import styled from 'styled-components';
import intl from 'react-intl-universal';
import {
Button,
Popover,
PopoverInteractionKind,
FormGroup,
Position,
Classes,
} from '@blueprintjs/core';
import { ExchangeRateInputGroup, Icon } from 'components';
export function ExchangeRateMutedField({
name,
toCurrency,
fromCurrency,
date,
exchangeRate,
exchangeRateFieldProps,
popoverProps,
}) {
const content = (
<ExchangeRateFormGroupContent>
<ExchangeRateInputGroup
name={name}
fromCurrency={fromCurrency}
toCurrency={toCurrency}
{...exchangeRateFieldProps}
/>
</ExchangeRateFormGroupContent>
);
return (
<ExchangeRateFormGroup label={`As on ${date},`}>
<Popover
content={content}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.RIGHT_TOP}
modifiers={{
offset: { offset: '0, 4' },
}}
{...popoverProps}
minimal={true}
usePortal={false}
target={<div />}
>
<ExchangeRateButton>
1 {fromCurrency} = {exchangeRate} {toCurrency}
<Button
className={Classes.MINIMAL}
rightIcon={<Icon icon="pen-18" iconSize={14} />}
small={true}
/>
</ExchangeRateButton>
</Popover>
</ExchangeRateFormGroup>
);
}
const ExchangeRateFormGroup = styled(FormGroup)`
&.bp3-form-group {
label.bp3-label {
font-size: 12px;
opacity: 0.7;
line-height: 1;
margin-bottom: 5px;
}
}
`;
const ExchangeRateButton = styled.div`
display: flex;
align-items: center;
font-size: 13px;
font-weight: 400;
color: #0d244a;
position: relative;
padding-right: 28px;
.bp3-button {
position: absolute;
right: 0;
}
`;
const ExchangeRateFormGroupContent = styled.div`
padding: 5px 0;
.bp3-form-group {
padding: 2px;
margin: 2px 4px !important;
}
`;

View File

@@ -1 +1,2 @@
export * from './ExchangeRateInput'; export * from './ExchangeRateInput';
export * from './ExchangeRateMutedField'

View File

@@ -2,7 +2,8 @@ import React, { useMemo, useCallback } from 'react';
import moment from 'moment'; import moment from 'moment';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { If, FormattedMessage as T } from 'components'; import If from '../Utils/If';
import { FormattedMessage as T } from '../FormattedMessage';
import { import {
FinancialSheetRoot, FinancialSheetRoot,
FinancialSheetFooterCurrentTime, FinancialSheetFooterCurrentTime,

View File

@@ -2,7 +2,8 @@ import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { Align } from 'common'; import { Align } from 'common';
import { SkeletonText, DataTable } from 'components'; import { SkeletonText } from 'components';
import DataTable from '../../components/DataTable'
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows'; import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton'; import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';

View File

@@ -0,0 +1,9 @@
import styled from 'styled-components';
import DataTable from '../DataTable';
export const ReportDataTable = styled(DataTable)`
.table .tbody .tr.no-results:last-of-type .td {
border-bottom: 1px solid #ddd;
}
`;

View File

@@ -1,2 +1,3 @@
export * from './FinancialSheet'; export * from './FinancialSheet';
export * from './FinancialSheetSkeleton'; export * from './FinancialSheetSkeleton';
export * from './ReportDataTable';

View File

@@ -0,0 +1,44 @@
import React from 'react';
import styled from 'styled-components';
import { Navbar } from '@blueprintjs/core';
/**
* Form the topbar.
* @param {JSX.Element} children
* @returns {JSX.Element}
*/
export function FormTopbar({ className, children }) {
return <FormTopBarRoot className={className}>{children}</FormTopBarRoot>;
}
const FormTopBarRoot = styled(Navbar)`
box-shadow: 0 0 0;
border-bottom: 1px solid #c7d5db;
height: 35px;
padding: 0 20px;
.bp3-navbar-group {
height: 35px;
}
.bp3-navbar-divider {
border-left-color: #d2dce2;
}
.bp3-skeleton {
max-height: 10px;
}
.bp3-button {
&:hover {
background: rgba(167, 182, 194, 0.12);
color: #32304a;
}
}
`;
export const DetailsBarSkeletonBase = styled.div`
letter-spacing: 10px;
margin-right: 10px;
margin-left: 10px;
font-size: 8px;
width: 140px;
height: 10px;
`;

View File

@@ -5,6 +5,8 @@ import {
Checkbox, Checkbox,
RadioGroup, RadioGroup,
Switch, Switch,
EditableText,
TextArea,
} from '@blueprintjs-formik/core'; } from '@blueprintjs-formik/core';
import { Select, MultiSelect } from '@blueprintjs-formik/select'; import { Select, MultiSelect } from '@blueprintjs-formik/select';
@@ -17,4 +19,6 @@ export {
Switch as FSwitch, Switch as FSwitch,
Select as FSelect, Select as FSelect,
MultiSelect as FMultiSelect, MultiSelect as FMultiSelect,
EditableText as FEditableText,
TextArea as FTextArea,
}; };

View File

@@ -1,7 +1,9 @@
import { useFormikContext } from 'formik';
import { useDeepCompareEffect } from 'hooks/utils'; import { useDeepCompareEffect } from 'hooks/utils';
export function FormikObserver({ onChange, values }) { export function FormikObserver({ onChange }) {
const { values } = useFormikContext();
useDeepCompareEffect(() => { useDeepCompareEffect(() => {
onChange(values); onChange(values);
}, [values]); }, [values]);

View File

@@ -0,0 +1,12 @@
import React from 'react';
import styled from 'styled-components';
export function Paper({ children, className }) {
return <PaperRoot className={className}>{children}</PaperRoot>;
}
const PaperRoot = styled.div`
border: 1px solid #d2dce2;
background: #fff;
padding: 10px;
`;

View File

@@ -0,0 +1 @@
export * from './Paper';

View File

@@ -28,7 +28,7 @@ export default function Sidebar({ dashboardContentRef }) {
* @returns {React.JSX} * @returns {React.JSX}
*/ */
function SidebarFooterVersion() { function SidebarFooterVersion() {
const { REACT_APP_VERSION: VERSION } = process.env; const { VERSION } = process.env;
if (!VERSION) { if (!VERSION) {
return null; return null;

View File

@@ -9,3 +9,13 @@ export const CurrencyTag = styled.span`
line-height: 1; line-height: 1;
margin-left: 4px; margin-left: 4px;
`; `;
export const BaseCurrencyRoot = styled.div`
display: flex;
align-items: center;
font-size: 10px;
margin-left: 4px;
> span {
background: #5c7080;
}
`;

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
export const FlagIcon = ({ countryCode, className }) => { export const FlagIcon = ({ currencyCode, className }) => {
const source = `/icons/flags/${countryCode}.svg`; const source = `/icons/flags/${currencyCode}.svg`;
return <img alt="flag" src={source} className={className} />; return <img alt="flag" src={source} className={className} />;
}; };

View File

@@ -2,6 +2,7 @@ import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
export const TotalLineBorderStyle = { export const TotalLineBorderStyle = {
None: 'None',
SingleDark: 'SingleDark', SingleDark: 'SingleDark',
DoubleDark: 'DoubleDark', DoubleDark: 'DoubleDark',
}; };
@@ -80,6 +81,11 @@ export const TotalLineRoot = styled.div`
` `
border-bottom: 1px double #000; border-bottom: 1px double #000;
`} `}
${(props) =>
props.borderStyle === TotalLineBorderStyle.None &&
`
border-bottom-color: transparent;
`}
${(props) => ${(props) =>
props.textStyle === TotalLineTextStyle.Bold && props.textStyle === TotalLineTextStyle.Bold &&
` `

View File

@@ -1,23 +1,25 @@
import React from 'react'; import React from 'react';
import * as R from 'ramda'; import * as R from 'ramda';
import { ButtonLink } from 'components'; import { ButtonLink } from '../Button';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
function VendorDrawerLinkComponent({ function VendorDrawerLinkComponent({
// #ownProps // #ownProps
children, children,
vendorId, vendorId,
className,
// #withDrawerActions // #withDrawerActions
openDrawer, openDrawer,
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleVendorDrawer = () => { const handleVendorDrawer = (event) => {
openDrawer('vendor-details-drawer', { vendorId }); openDrawer('vendor-details-drawer', { vendorId });
event.preventDefault();
}; };
return <ButtonLink onClick={handleVendorDrawer}>{children}</ButtonLink>; return <ButtonLink className={className} onClick={handleVendorDrawer}>{children}</ButtonLink>;
} }
export const VendorDrawerLink = R.compose(withDrawerActions)(VendorDrawerLinkComponent); export const VendorDrawerLink = R.compose(withDrawerActions)(VendorDrawerLinkComponent);

View File

@@ -40,8 +40,8 @@ const warehouseItemRenderer = (
active={modifiers.active} active={modifiers.active}
disabled={modifiers.disabled} disabled={modifiers.disabled}
icon={isSelected ? 'tick' : 'blank'} icon={isSelected ? 'tick' : 'blank'}
text={warehouse.name.toString()} text={warehouse.name}
label={warehouse.code.toString()} label={warehouse.code}
key={warehouse.id} key={warehouse.id}
onClick={handleClick} onClick={handleClick}
/> />
@@ -52,7 +52,7 @@ const warehouseSelectProps = {
itemPredicate: warehouseItemPredicate, itemPredicate: warehouseItemPredicate,
itemRenderer: warehouseItemRenderer, itemRenderer: warehouseItemRenderer,
valueAccessor: (item) => item.id, valueAccessor: (item) => item.id,
labelAccessor: (item) => item.label, labelAccessor: (item) => item.code,
tagRenderer: (item) => item.name, tagRenderer: (item) => item.name,
}; };

View File

@@ -40,7 +40,7 @@ const warehouseItemRenderer = (
<MenuItem <MenuItem
active={modifiers.active} active={modifiers.active}
disabled={modifiers.disabled} disabled={modifiers.disabled}
label={warehouse.name.toString()} label={warehouse.code}
key={warehouse.id} key={warehouse.id}
onClick={handleClick} onClick={handleClick}
text={text} text={text}

View File

@@ -55,7 +55,7 @@ import AvaterCell from './AvaterCell';
import { ItemsMultiSelect } from './Items'; import { ItemsMultiSelect } from './Items';
import MoreMenuItems from './MoreMenutItems'; import MoreMenuItems from './MoreMenutItems';
import CustomSelectList from './CustomSelectList'; import CustomSelectList from './CustomSelectList';
import BaseCurrency from './BaseCurrency'; import { ExchangeRateDetailItem } from './DetailExchangeRate';
export * from './Dialog'; export * from './Dialog';
export * from './Menu'; export * from './Menu';
@@ -102,6 +102,9 @@ export * from './ExchangeRate';
export * from './Branches'; export * from './Branches';
export * from './Warehouses'; export * from './Warehouses';
export * from './Currencies'; export * from './Currencies';
export * from './FormTopbar'
export * from './Paper';
export * from './Accounts'
const Hint = FieldHint; const Hint = FieldHint;
@@ -167,7 +170,7 @@ export {
MoneyFieldCell, MoneyFieldCell,
ItemsMultiSelect, ItemsMultiSelect,
AvaterCell, AvaterCell,
BaseCurrency,
MoreMenuItems, MoreMenuItems,
CustomSelectList, CustomSelectList,
ExchangeRateDetailItem,
}; };

View File

@@ -70,6 +70,20 @@ export const financialReportMenus = [
subject: AbilitySubject.Report, subject: AbilitySubject.Report,
ability: ReportsAction.READ_AP_AGING_SUMMARY, ability: ReportsAction.READ_AP_AGING_SUMMARY,
}, },
{
title: <T id={'report.balance_sheet_comparison.title'} />,
desc: <T id={'report.balance_sheet_comparison.desc'} />,
link: 'financial-reports/balance-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
subject: AbilitySubject.Report,
ability: ReportsAction.READ_BALANCE_SHEET,
},
{
title: <T id={'report.profit_loss_sheet_comparison.title'} />,
desc: <T id={'report.profit_loss_sheet_comparison.desc'} />,
link: '/financial-reports/profit-loss-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
subject: AbilitySubject.Report,
ability: ReportsAction.READ_PROFIT_LOSS,
},
], ],
}, },
]; ];

View File

@@ -641,14 +641,14 @@ export default [
ability: ReportsAction.READ_AP_AGING_SUMMARY, ability: ReportsAction.READ_AP_AGING_SUMMARY,
}, },
}, },
{ // {
text: <T id={'realized_gain_or_loss.label'} />, // text: <T id={'realized_gain_or_loss.label'} />,
href: '/financial-reports/realized-gain-loss', // href: '/financial-reports/realized-gain-loss',
}, // },
{ // {
text: <T id={'unrealized_gain_or_loss.label'} />, // text: <T id={'unrealized_gain_or_loss.label'} />,
href: '/financial-reports/unrealized-gain-loss', // href: '/financial-reports/unrealized-gain-loss',
}, // },
{ {
text: <T id={'Sales/Purchases'} />, text: <T id={'Sales/Purchases'} />,
label: true, label: true,

View File

@@ -13,13 +13,13 @@ const Schema = Yup.object().shape({
.min(1) .min(1)
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(intl.get('journal_type')), .label(intl.get('journal_type')),
date: Yup.date() date: Yup.date().required().label(intl.get('date')),
.required()
.label(intl.get('date')),
currency_code: Yup.string().max(3), currency_code: Yup.string().max(3),
publish: Yup.boolean(), publish: Yup.boolean(),
branch_id: Yup.string(),
reference: Yup.string().nullable().min(1).max(DATATYPES_LENGTH.STRING), reference: Yup.string().nullable().min(1).max(DATATYPES_LENGTH.STRING),
description: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(), description: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),
exchange_rate: Yup.number(),
entries: Yup.array().of( entries: Yup.array().of(
Yup.object().shape({ Yup.object().shape({
credit: Yup.number().nullable(), credit: Yup.number().nullable(),

View File

@@ -10,7 +10,7 @@ import { useMakeJournalFormContext } from './MakeJournalProvider';
* Make journal entries field. * Make journal entries field.
*/ */
export default function MakeJournalEntriesField() { export default function MakeJournalEntriesField() {
const { accounts, contacts } = useMakeJournalFormContext(); const { accounts, contacts ,branches } = useMakeJournalFormContext();
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_BODY)}> <div className={classNames(CLASSES.PAGE_FORM_BODY)}>
@@ -18,6 +18,7 @@ export default function MakeJournalEntriesField() {
name={'entries'} name={'entries'}
contacts={contacts} contacts={contacts}
accounts={accounts} accounts={accounts}
branches={branches}
shouldUpdate={entriesFieldShouldUpdate} shouldUpdate={entriesFieldShouldUpdate}
> >
{({ {({

View File

@@ -17,6 +17,7 @@ import MakeJournalFormFloatingActions from './MakeJournalFormFloatingActions';
import MakeJournalEntriesField from './MakeJournalEntriesField'; import MakeJournalEntriesField from './MakeJournalEntriesField';
import MakeJournalFormFooter from './MakeJournalFormFooter'; import MakeJournalFormFooter from './MakeJournalFormFooter';
import MakeJournalFormDialogs from './MakeJournalFormDialogs'; import MakeJournalFormDialogs from './MakeJournalFormDialogs';
import MakeJournalFormTopBar from './MakeJournalFormTopBar';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization'; import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
@@ -58,6 +59,7 @@ function MakeJournalEntriesForm({
journalNumberPrefix, journalNumberPrefix,
journalNextNumber, journalNextNumber,
); );
// Form initial values. // Form initial values.
const initialValues = useMemo( const initialValues = useMemo(
() => ({ () => ({
@@ -68,12 +70,12 @@ function MakeJournalEntriesForm({
: { : {
...defaultManualJournal, ...defaultManualJournal,
...(journalAutoIncrement && { ...(journalAutoIncrement && {
journal_number: defaultTo(journalNumber, ''), journal_number: journalNumber,
}), }),
currency_code: base_currency, currency_code: base_currency,
}), }),
}), }),
[manualJournal, base_currency, journalNumber], [manualJournal, base_currency, journalNumber, journalAutoIncrement],
); );
// Handle the form submiting. // Handle the form submiting.
@@ -107,7 +109,7 @@ function MakeJournalEntriesForm({
return; return;
} }
const form = { const form = {
...omit(values, ['journal_number', 'journal_number_manually']), ...omit(values, ['journal_number_manually']),
...(values.journal_number_manually && { ...(values.journal_number_manually && {
journal_number: values.journal_number, journal_number: values.journal_number,
}), }),
@@ -169,6 +171,7 @@ function MakeJournalEntriesForm({
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<Form> <Form>
<MakeJournalFormTopBar />
<MakeJournalEntriesHeader /> <MakeJournalEntriesHeader />
<MakeJournalEntriesField /> <MakeJournalEntriesField />
<MakeJournalFormFooter /> <MakeJournalFormFooter />
@@ -185,7 +188,7 @@ function MakeJournalEntriesForm({
export default compose( export default compose(
withMediaActions, withMediaActions,
withSettings(({ manualJournalsSettings }) => ({ withSettings(({ manualJournalsSettings }) => ({
journalNextNumber: parseInt(manualJournalsSettings?.nextNumber, 10), journalNextNumber: manualJournalsSettings?.nextNumber,
journalNumberPrefix: manualJournalsSettings?.numberPrefix, journalNumberPrefix: manualJournalsSettings?.numberPrefix,
journalAutoIncrement: manualJournalsSettings?.autoIncrement, journalAutoIncrement: manualJournalsSettings?.autoIncrement,
})), })),

View File

@@ -28,6 +28,7 @@ import {
} from 'components'; } from 'components';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
import { JournalExchangeRateInputField } from './components';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import { import {
currenciesFieldShouldUpdate, currenciesFieldShouldUpdate,
@@ -52,14 +53,14 @@ function MakeJournalEntriesHeader({
// Handle journal number change. // Handle journal number change.
const handleJournalNumberChange = () => { const handleJournalNumberChange = () => {
openDialog('journal-number-form', {}); openDialog('journal-number-form');
}; };
// Handle journal number blur. // Handle journal number blur.
const handleJournalNoBlur = (form, field) => (event) => { const handleJournalNoBlur = (form, field) => (event) => {
const newValue = event.target.value; const newValue = event.target.value;
if (field.value !== newValue) { if (field.value !== newValue && journalAutoIncrement) {
openDialog('journal-number-form', { openDialog('journal-number-form', {
initialFormValues: { initialFormValues: {
manualTransactionNo: newValue, manualTransactionNo: newValue,
@@ -201,13 +202,19 @@ function MakeJournalEntriesHeader({
selectedCurrencyCode={value} selectedCurrencyCode={value}
onCurrencySelected={(currencyItem) => { onCurrencySelected={(currencyItem) => {
form.setFieldValue('currency_code', currencyItem.currency_code); form.setFieldValue('currency_code', currencyItem.currency_code);
form.setFieldValue('exchange_rate', '');
}} }}
defaultSelectText={value} defaultSelectText={value}
disabled={true}
/> />
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/* ----------- Exchange rate ----------- */}
<JournalExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
</div> </div>
); );
} }

View File

@@ -21,15 +21,16 @@ export default function MakeJournalEntriesTable({
entries, entries,
defaultEntry, defaultEntry,
error, error,
initialLinesNumber = 4, initialLinesNumber = 1,
minLinesNumber = 4, minLinesNumber = 1,
currencyCode, currencyCode,
}) { }) {
const { accounts, contacts } = useMakeJournalFormContext(); const { accounts, contacts, branches } = useMakeJournalFormContext();
// Memorized data table columns. // Memorized data table columns.
const columns = useJournalTableEntriesColumns(); const columns = useJournalTableEntriesColumns();
// Handles update datatable data. // Handles update datatable data.
const handleUpdateData = (rowIndex, columnId, value) => { const handleUpdateData = (rowIndex, columnId, value) => {
const newRows = compose( const newRows = compose(
@@ -62,13 +63,13 @@ export default function MakeJournalEntriesTable({
data={entries} data={entries}
sticky={true} sticky={true}
totalRow={true} totalRow={true}
footer={true}
payload={{ payload={{
accounts, accounts,
errors: error, errors: error,
updateData: handleUpdateData, updateData: handleUpdateData,
removeRow: handleRemoveRow, removeRow: handleRemoveRow,
contacts, contacts,
branches,
autoFocus: ['account_id', 0], autoFocus: ['account_id', 0],
currencyCode, currencyCode,
}} }}

View File

@@ -1,44 +1,29 @@
import React from 'react'; import React from 'react';
import { FastField } from 'formik';
import classNames from 'classnames'; import classNames from 'classnames';
import styled from 'styled-components';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import { FormGroup, TextArea } from '@blueprintjs/core'; import { Row, Col, Paper } from 'components';
import { FormattedMessage as T } from 'components'; import { MakeJournalFormFooterLeft } from './MakeJournalFormFooterLeft';
import { Postbox, ErrorMessage, Row, Col } from 'components'; import { MakeJournalFormFooterRight } from './MakeJournalFormFooterRight';
import Dragzone from 'components/Dragzone';
import { inputIntent } from 'utils';
export default function MakeJournalFormFooter() { export default function MakeJournalFormFooter() {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}> <div className={classNames(CLASSES.PAGE_FORM_FOOTER)}>
<Postbox title={<T id={'journal_details'} />} defaultOpen={false}> <MakeJournalFooterPaper>
<Row> <Row>
<Col md={8}> <Col md={8}>
<FastField name={'description'}> <MakeJournalFormFooterLeft />
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="description" />}
fill={true}
>
<TextArea fill={true} {...field} />
</FormGroup>
)}
</FastField>
</Col> </Col>
<Col md={4}> <Col md={4}>
<Dragzone <MakeJournalFormFooterRight />
initialFiles={[]}
// onDrop={handleDropFiles}
// onDeleteFile={handleDeleteFile}
hint={<T id={'attachments_maximum'} />}
/>
</Col> </Col>
</Row> </Row>
</Postbox> </MakeJournalFooterPaper>
</div> </div>
); );
} }
const MakeJournalFooterPaper = styled(Paper)`
padding: 20px;
`;

View File

@@ -0,0 +1,32 @@
import React from 'react';
import styled from 'styled-components';
import { FFormGroup, FEditableText, FormattedMessage as T } from 'components';
export function MakeJournalFormFooterLeft() {
return (
<React.Fragment>
{/* --------- Description --------- */}
<DescriptionFormGroup
label={<T id={'description'} />}
name={'description'}
>
<FEditableText
name={'description'}
placeholder={<T id={'make_jorunal.decscrption.placeholder'} />}
/>
</DescriptionFormGroup>
</React.Fragment>
);
}
const DescriptionFormGroup = styled(FFormGroup)`
&.bp3-form-group {
.bp3-label {
font-size: 12px;
margin-bottom: 12px;
}
.bp3-form-content {
margin-left: 10px;
}
}
`;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import styled from 'styled-components';
import {
T,
TotalLines,
TotalLine,
TotalLineBorderStyle,
TotalLineTextStyle,
} from 'components';
import { useJournalTotals } from './utils';
export function MakeJournalFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useJournalTotals();
return (
<MakeJouranlTotalLines>
<TotalLine
title={<T id={'make_journal.label.subtotal'} />}
value={formattedSubtotal}
borderStyle={TotalLineBorderStyle.None}
/>
<TotalLine
title={<T id={'make_journal.label.total'} />}
value={formattedTotal}
textStyle={TotalLineTextStyle.Bold}
/>
</MakeJouranlTotalLines>
);
}
const MakeJouranlTotalLines = styled(TotalLines)`
width: 100%;
color: #555555;
`;

View File

@@ -0,0 +1,68 @@
import React from 'react';
import intl from 'react-intl-universal';
import { Button, Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
import styled from 'styled-components';
import { useSetPrimaryBranchToForm } from './utils';
import { useFeatureCan } from 'hooks/state';
import {
Icon,
BranchSelect,
FeatureCan,
FormTopbar,
DetailsBarSkeletonBase,
} from 'components';
import { useMakeJournalFormContext } from './MakeJournalProvider';
import { Features } from 'common';
/**
* Make journal form topbar.
* @returns
*/
export default function MakeJournalFormTopBar() {
// Features guard.
const { featureCan } = useFeatureCan();
// Sets the primary branch to form.
useSetPrimaryBranchToForm();
// Can't display the navigation bar if branches feature is not enabled.
if (!featureCan(Features.Branches)) {
return null;
}
return (
<FormTopbar>
<NavbarGroup align={Alignment.LEFT}>
<FeatureCan feature={Features.Branches}>
<MakeJournalFormSelectBranch />
</FeatureCan>
</NavbarGroup>
</FormTopbar>
);
}
function MakeJournalFormSelectBranch() {
// Invoice form context.
const { branches, isBranchesLoading } = useMakeJournalFormContext();
return isBranchesLoading ? (
<DetailsBarSkeletonBase className={Classes.SKELETON} />
) : (
<BranchSelect
name={'branch_id'}
branches={branches}
input={MakeJournalBranchSelectButton}
popoverProps={{ minimal: true }}
/>
);
}
function MakeJournalBranchSelectButton({ label }) {
return (
<Button
text={intl.get('make_journal.branch_button.label', { label })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/>
);
}

View File

@@ -1,4 +1,7 @@
import React, { createContext, useState } from 'react'; import React, { createContext, useState } from 'react';
import { isEqual, isUndefined } from 'lodash';
import { Features } from 'common';
import { useFeatureCan } from 'hooks/state';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { import {
useAccounts, useAccounts,
@@ -8,7 +11,8 @@ import {
useCreateJournal, useCreateJournal,
useEditJournal, useEditJournal,
useSettings, useSettings,
useSettingsManualJournals useBranches,
useSettingsManualJournals,
} from 'hooks/query'; } from 'hooks/query';
const MakeJournalFormContext = createContext(); const MakeJournalFormContext = createContext();
@@ -16,15 +20,17 @@ const MakeJournalFormContext = createContext();
/** /**
* Make journal form provider. * Make journal form provider.
*/ */
function MakeJournalProvider({ journalId, ...props }) { function MakeJournalProvider({ journalId, query, ...props }) {
// Features guard.
const { featureCan } = useFeatureCan();
const isBranchFeatureCan = featureCan(Features.Branches);
// Load the accounts list. // Load the accounts list.
const { data: accounts, isLoading: isAccountsLoading } = useAccounts(); const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
// Load the customers list. // Load the customers list.
const { const { data: contacts, isLoading: isContactsLoading } =
data: contacts, useAutoCompleteContacts();
isLoading: isContactsLoading,
} = useAutoCompleteContacts();
// Load the currencies list. // Load the currencies list.
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
@@ -43,15 +49,27 @@ function MakeJournalProvider({ journalId, ...props }) {
// Loading the journal settings. // Loading the journal settings.
const { isLoading: isSettingsLoading } = useSettingsManualJournals(); const { isLoading: isSettingsLoading } = useSettingsManualJournals();
// Fetches the branches list.
const {
data: branches,
isLoading: isBranchesLoading,
isSuccess: isBranchesSuccess,
} = useBranches(query, { enabled: isBranchFeatureCan });
// Submit form payload. // Submit form payload.
const [submitPayload, setSubmitPayload] = useState({}); const [submitPayload, setSubmitPayload] = useState({});
// Determines whether the warehouse and branches are loading.
const isFeatureLoading = isBranchesLoading;
const provider = { const provider = {
accounts, accounts,
contacts, contacts,
currencies, currencies,
manualJournal, manualJournal,
branches,
createJournalMutate, createJournalMutate,
editJournalMutate, editJournalMutate,
@@ -59,12 +77,13 @@ function MakeJournalProvider({ journalId, ...props }) {
isContactsLoading, isContactsLoading,
isCurrenciesLoading, isCurrenciesLoading,
isJournalLoading, isJournalLoading,
isFeatureLoading,
isSettingsLoading, isSettingsLoading,
isBranchesSuccess,
isNewMode: !journalId, isNewMode: !journalId,
submitPayload, submitPayload,
setSubmitPayload setSubmitPayload,
}; };
return ( return (

View File

@@ -1,15 +1,28 @@
import React from 'react'; import React from 'react';
import { Intent, Position, Button, Tooltip } from '@blueprintjs/core'; import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { Popover2 } from '@blueprintjs/popover2';
import { Icon, Money, Hint } from 'components'; import { useFormikContext } from 'formik';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import {
ExchangeRateInputGroup,
Icon,
Hint,
FormattedMessage as T,
} from 'components';
import { import {
AccountsListFieldCell, AccountsListFieldCell,
MoneyFieldCell, MoneyFieldCell,
InputGroupCell, InputGroupCell,
ContactsListFieldCell, ContactsListFieldCell,
BranchesListFieldCell,
} from 'components/DataTableCells'; } from 'components/DataTableCells';
import { safeSumBy } from 'utils';
import { CellType, Features, Align } from 'common';
import { useFeatureCan } from 'hooks/state';
import { useCurrentOrganization } from 'hooks/state';
import { useJournalIsForeign } from './utils';
/** /**
* Contact header cell. * Contact header cell.
@@ -40,42 +53,6 @@ export function DebitHeaderCell({ payload: { currencyCode } }) {
return intl.get('debit_currency', { currency: currencyCode }); return intl.get('debit_currency', { currency: currencyCode });
} }
/**
* Account footer cell.
*/
function AccountFooterCell({ payload: { currencyCode } }) {
return (
<span>
{intl.get('total_currency', { currency: currencyCode })}
</span>
);
}
/**
* Total credit table footer cell.
*/
function TotalCreditFooterCell({ payload: { currencyCode }, rows }) {
const credit = safeSumBy(rows, 'original.credit');
return (
<span>
<Money amount={credit} currency={currencyCode} />
</span>
);
}
/**
* Total debit table footer cell.
*/
function TotalDebitFooterCell({ payload: { currencyCode }, rows }) {
const debit = safeSumBy(rows, 'original.debit');
return (
<span>
<Money amount={debit} currency={currencyCode} />
</span>
);
}
/** /**
* Actions cell renderer. * Actions cell renderer.
*/ */
@@ -86,95 +63,123 @@ export const ActionsCellRenderer = ({
data, data,
payload, payload,
}) => { }) => {
const onClickRemoveRole = () => { const handleClickRemoveRole = () => {
payload.removeRow(index); payload.removeRow(index);
}; };
return ( const exampleMenu = (
<Tooltip content={<T id={'remove_the_line'} />} position={Position.LEFT}> <Menu>
<Button <MenuItem
icon={<Icon icon="times-circle" iconSize={14} />} onClick={handleClickRemoveRole}
iconSize={14} text={intl.get('make_journal.entries.remove_row')}
className="ml2"
minimal={true}
intent={Intent.DANGER}
onClick={onClickRemoveRole}
/> />
</Tooltip> </Menu>
);
return (
<Popover2 content={exampleMenu} placement="left-start">
<Button
icon={<Icon icon={'more-13'} iconSize={13} />}
iconSize={14}
className="m12"
minimal={true}
/>
</Popover2>
); );
}; };
ActionsCellRenderer.cellType = CellType.Button;
/** /**
* Retrieve columns of make journal entries table. * Retrieve columns of make journal entries table.
*/ */
export const useJournalTableEntriesColumns = () => { export const useJournalTableEntriesColumns = () => {
const { featureCan } = useFeatureCan();
return React.useMemo( return React.useMemo(
() => [ () => [
{
Header: '#',
accessor: 'index',
Cell: ({ row: { index } }) => <span>{index + 1}</span>,
className: 'index',
width: 40,
disableResizing: true,
disableSortBy: true,
sticky: 'left',
},
{ {
Header: intl.get('account'), Header: intl.get('account'),
id: 'account_id', id: 'account_id',
accessor: 'account_id', accessor: 'account_id',
Cell: AccountsListFieldCell, Cell: AccountsListFieldCell,
Footer: AccountFooterCell,
className: 'account',
disableSortBy: true, disableSortBy: true,
width: 160, width: 160,
fieldProps: { allowCreate: true } fieldProps: { allowCreate: true },
}, },
{ {
Header: CreditHeaderCell, Header: CreditHeaderCell,
accessor: 'credit', accessor: 'credit',
Cell: MoneyFieldCell, Cell: MoneyFieldCell,
Footer: TotalCreditFooterCell,
className: 'credit',
disableSortBy: true, disableSortBy: true,
width: 100, width: 100,
align: Align.Right,
}, },
{ {
Header: DebitHeaderCell, Header: DebitHeaderCell,
accessor: 'debit', accessor: 'debit',
Cell: MoneyFieldCell, Cell: MoneyFieldCell,
Footer: TotalDebitFooterCell,
className: 'debit',
disableSortBy: true, disableSortBy: true,
width: 100, width: 100,
align: Align.Right,
}, },
{ {
Header: ContactHeaderCell, Header: ContactHeaderCell,
id: 'contact_id', id: 'contact_id',
accessor: 'contact_id', accessor: 'contact_id',
Cell: ContactsListFieldCell, Cell: ContactsListFieldCell,
className: 'contact',
disableSortBy: true, disableSortBy: true,
width: 120, width: 120,
}, },
...(featureCan(Features.Branches)
? [
{
Header: intl.get('branch'),
id: 'branch_id',
accessor: 'branch_id',
Cell: BranchesListFieldCell,
disableSortBy: true,
width: 120,
},
]
: []),
{ {
Header: intl.get('note'), Header: intl.get('note'),
accessor: 'note', accessor: 'note',
Cell: InputGroupCell, Cell: InputGroupCell,
disableSortBy: true, disableSortBy: true,
className: 'note',
width: 200, width: 200,
}, },
{ {
Header: '', Header: '',
accessor: 'action', accessor: 'action',
Cell: ActionsCellRenderer, Cell: ActionsCellRenderer,
className: 'actions',
disableSortBy: true, disableSortBy: true,
disableResizing: true, disableResizing: true,
width: 45, width: 45,
align: Align.Center,
}, },
], ],
[], [],
); );
}; };
/**
* Journal exchange rate input field.
* @returns {JSX.Element}
*/
export function JournalExchangeRateInputField({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignJouranl = useJournalIsForeign();
// Can't continue if the customer is not foreign.
if (!isForeignJouranl) {
return null;
}
return (
<ExchangeRateInputGroup
fromCurrency={values.currency_code}
toCurrency={currentOrganization.base_currency}
{...props}
/>
);
}

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { sumBy, setWith, toSafeInteger, get } from 'lodash'; import { sumBy, setWith, toSafeInteger, get, first } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import * as R from 'ramda'; import * as R from 'ramda';
import { import {
@@ -9,11 +9,15 @@ import {
repeatValue, repeatValue,
transformToForm, transformToForm,
defaultFastFieldShouldUpdate, defaultFastFieldShouldUpdate,
ensureEntriesHasEmptyLine ensureEntriesHasEmptyLine,
formattedAmount,
safeSumBy,
} from 'utils'; } from 'utils';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import { useMakeJournalFormContext } from './MakeJournalProvider';
import { useCurrentOrganization } from 'hooks/state';
const ERROR = { const ERROR = {
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS', JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
@@ -26,25 +30,30 @@ const ERROR = {
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT', ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
}; };
export const MIN_LINES_NUMBER = 4; export const MIN_LINES_NUMBER = 1;
export const DEFAULT_LINES_NUMBER = 1;
export const defaultEntry = { export const defaultEntry = {
account_id: '', account_id: '',
credit: '', credit: '',
debit: '', debit: '',
contact_id: '', contact_id: '',
branch_id: '',
note: '', note: '',
}; };
export const defaultManualJournal = { export const defaultManualJournal = {
journal_number: '', journal_number: '',
journal_number_manually: false,
journal_type: 'Journal', journal_type: 'Journal',
date: moment(new Date()).format('YYYY-MM-DD'), date: moment(new Date()).format('YYYY-MM-DD'),
description: '', description: '',
reference: '', reference: '',
currency_code: '', currency_code: '',
publish: '', publish: '',
entries: [...repeatValue(defaultEntry, 4)], branch_id: '',
exchange_rate: 1,
entries: [...repeatValue(defaultEntry, DEFAULT_LINES_NUMBER)],
}; };
// Transform to edit form. // Transform to edit form.
@@ -179,6 +188,7 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
return ( return (
newProps.accounts !== oldProps.accounts || newProps.accounts !== oldProps.accounts ||
newProps.contacts !== oldProps.contacts || newProps.contacts !== oldProps.contacts ||
newProps.branches !== oldProps.branches ||
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };
@@ -192,3 +202,63 @@ export const currenciesFieldShouldUpdate = (newProps, oldProps) => {
defaultFastFieldShouldUpdate(newProps, oldProps) defaultFastFieldShouldUpdate(newProps, oldProps)
); );
}; };
export const useSetPrimaryBranchToForm = () => {
const { setFieldValue } = useFormikContext();
const { branches, isBranchesSuccess } = useMakeJournalFormContext();
React.useEffect(() => {
if (isBranchesSuccess) {
const primaryBranch = branches.find((b) => b.primary) || first(branches);
if (primaryBranch) {
setFieldValue('branch_id', primaryBranch.id);
}
}
}, [isBranchesSuccess, setFieldValue, branches]);
};
/**
* Retreives the Journal totals.
*/
export const useJournalTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total.
const totalCredit = safeSumBy(entries, 'credit');
const totalDebit = safeSumBy(entries, 'debit');
const total = Math.max(totalCredit, totalDebit);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
formattedTotal,
formattedSubtotal,
};
};
/**
* Detarmines whether the expenses has foreign .
* @returns {boolean}
*/
export const useJournalIsForeign = () => {
const { values } = useFormikContext();
const currentOrganization = useCurrentOrganization();
const isForeignJournal = React.useMemo(
() => values.currency_code !== currentOrganization.base_currency,
[values.currency_code, currentOrganization.base_currency],
);
return isForeignJournal;
};

View File

@@ -15,6 +15,8 @@ import withSettings from '../Settings/withSettings';
import { useAccountsChartContext } from './AccountsChartProvider'; import { useAccountsChartContext } from './AccountsChartProvider';
import { useMemorizedColumnsWidths } from '../../hooks'; import { useMemorizedColumnsWidths } from '../../hooks';
import { AccountDialogAction } from '../Dialogs/AccountDialog/utils';
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
@@ -58,7 +60,10 @@ function AccountsDataTable({
// Handle edit account action. // Handle edit account action.
const handleEditAccount = (account) => { const handleEditAccount = (account) => {
openDialog('account-form', { action: 'edit', id: account.id }); openDialog('account-form', {
action: AccountDialogAction.Edit,
id: account.id,
});
}; };
// Handle view detail account. // Handle view detail account.
@@ -69,7 +74,7 @@ function AccountsDataTable({
// Handle new child button click. // Handle new child button click.
const handleNewChildAccount = (account) => { const handleNewChildAccount = (account) => {
openDialog('account-form', { openDialog('account-form', {
action: 'new_child', action: AccountDialogAction.NewChild,
parentAccountId: account.id, parentAccountId: account.id,
accountType: account.account_type, accountType: account.account_type,
}); });

View File

@@ -57,9 +57,7 @@ function BillTransactionDeleteAlert({
loading={isLoading} loading={isLoading}
> >
<p> <p>
<T <T id={`landed_cost.once_your_delete_this_located_landed_cost`} />
id={`Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?`}
/>
</p> </p>
</Alert> </Alert>
); );

View File

@@ -5,6 +5,7 @@ import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import { useDeleteBranch } from 'hooks/query'; import { useDeleteBranch } from 'hooks/query';
import { handleDeleteErrors } from '../../Preferences/Branches/utils';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions'; import withAlertActions from 'containers/Alert/withAlertActions';
@@ -24,7 +25,6 @@ function BranchDeleteAlert({
// #withAlertActions // #withAlertActions
closeAlert, closeAlert,
}) { }) {
const { mutateAsync: deleteBranch, isLoading } = useDeleteBranch(); const { mutateAsync: deleteBranch, isLoading } = useDeleteBranch();
// Handle cancel delete alert. // Handle cancel delete alert.
@@ -46,7 +46,9 @@ function BranchDeleteAlert({
response: { response: {
data: { errors }, data: { errors },
}, },
}) => {}, }) => {
handleDeleteErrors(errors);
},
) )
.finally(() => { .finally(() => {
closeAlert(name); closeAlert(name);

View File

@@ -3,7 +3,7 @@ import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core'; import { Intent, Alert } from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { useMarkPrimaryBranches } from 'hooks/query'; import { useMarkBranchAsPrimary } from 'hooks/query';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import withAlertActions from 'containers/Alert/withAlertActions'; import withAlertActions from 'containers/Alert/withAlertActions';
@@ -25,7 +25,7 @@ function BranchMarkPrimaryAlert({
closeAlert, closeAlert,
}) { }) {
const { mutateAsync: markPrimaryBranchMutate, isLoading } = const { mutateAsync: markPrimaryBranchMutate, isLoading } =
useMarkPrimaryBranches(); useMarkBranchAsPrimary();
// Handle cancel mark primary alert. // Handle cancel mark primary alert.
const handleCancelMarkPrimaryAlert = () => { const handleCancelMarkPrimaryAlert = () => {
@@ -49,8 +49,8 @@ function BranchMarkPrimaryAlert({
return ( return (
<Alert <Alert
cancelButtonText={<T id={'cancel'} />} // cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'make_primary'} />} // confirmButtonText={<T id={'make_primary'} />}
intent={Intent.WARNING} intent={Intent.WARNING}
isOpen={isOpen} isOpen={isOpen}
onCancel={handleCancelMarkPrimaryAlert} onCancel={handleCancelMarkPrimaryAlert}

View File

@@ -4,6 +4,7 @@ import { FormattedMessage as T, FormattedHTMLMessage } from 'components';
import { Intent, Alert } from '@blueprintjs/core'; import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import { useDeleteWarehouse } from 'hooks/query'; import { useDeleteWarehouse } from 'hooks/query';
import { handleDeleteErrors } from '../../Preferences/Warehouses/utils';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions'; import withAlertActions from 'containers/Alert/withAlertActions';
@@ -46,7 +47,9 @@ function WarehouseDeleteAlert({
response: { response: {
data: { errors }, data: { errors },
}, },
}) => {}, }) => {
handleDeleteErrors(errors);
},
) )
.finally(() => { .finally(() => {
closeAlert(name); closeAlert(name);

View File

@@ -0,0 +1,71 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { useTransferredWarehouseTransfer } from 'hooks/query';
import { AppToaster } from 'components';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* warehouse transfer transferred alert.
* @returns
*/
function TransferredWarehouseTransferAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { warehouseTransferId },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: transferredWarehouseTransferMutate, isLoading } =
useTransferredWarehouseTransfer();
// handle cancel alert.
const handleCancelAlert = () => {
closeAlert(name);
};
// Handle confirm alert.
const handleConfirmTransferred = () => {
transferredWarehouseTransferMutate(warehouseTransferId)
.then(() => {
AppToaster.show({
message: intl.get('warehouse_transfer.alert.transferred_warehouse'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'deliver'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelAlert}
onConfirm={handleConfirmTransferred}
loading={isLoading}
>
<p>
<T id={'warehouse_transfer.alert.are_you_sure_you_want_to_deliver'} />
</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(TransferredWarehouseTransferAlert);

View File

@@ -3,7 +3,7 @@ import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core'; import { Intent, Alert } from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { useMarkPrimaryWarehouse } from 'hooks/query'; import { useMarkWarehouseAsPrimary } from 'hooks/query';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import withAlertActions from 'containers/Alert/withAlertActions'; import withAlertActions from 'containers/Alert/withAlertActions';
@@ -24,14 +24,14 @@ function WarehouseMarkPrimaryAlert({
// #withAlertActions // #withAlertActions
closeAlert, closeAlert,
}) { }) {
const { mutateAsync: markPrimaryWarehouseMutate, isLoading } = // const { mutateAsync: markPrimaryWarehouseMutate, isLoading } =
useMarkPrimaryWarehouse(); // useMarkWarehouseAsPrimary();
// Handle cancel mark primary alert. // Handle cancel mark primary alert.
const handleCancelMarkPrimaryAlert = () => { const handleCancelMarkPrimaryAlert = () => {
closeAlert(name); closeAlert(name);
}; };
console.log(warehouseId, 'XX');
// andle cancel mark primary confirm. // andle cancel mark primary confirm.
const handleConfirmMarkPrimaryWarehouse = () => { const handleConfirmMarkPrimaryWarehouse = () => {
markPrimaryWarehouseMutate(warehouseId) markPrimaryWarehouseMutate(warehouseId)

View File

@@ -0,0 +1,71 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import intl from 'react-intl-universal';
import { Intent, Alert } from '@blueprintjs/core';
import { useInitiateWarehouseTransfer } from 'hooks/query';
import { AppToaster } from 'components';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
import withAlertActions from 'containers/Alert/withAlertActions';
import { compose } from 'utils';
/**
* warehouse transfer initiate alert.
* @returns
*/
function WarehouseTransferInitiateAlert({
name,
// #withAlertStoreConnect
isOpen,
payload: { warehouseTransferId },
// #withAlertActions
closeAlert,
}) {
const { mutateAsync: initialWarehouseTransferMutate, isLoading } =
useInitiateWarehouseTransfer();
// handle cancel alert.
const handleCancelAlert = () => {
closeAlert(name);
};
// Handle confirm alert.
const handleConfirmInitiated = () => {
initialWarehouseTransferMutate(warehouseTransferId)
.then(() => {
AppToaster.show({
message: intl.get('warehouse_transfer.alert.initiate_warehouse'),
intent: Intent.SUCCESS,
});
})
.catch((error) => {})
.finally(() => {
closeAlert(name);
});
};
return (
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'warehouse_transfer.label.initiate'} />}
intent={Intent.WARNING}
isOpen={isOpen}
onCancel={handleCancelAlert}
onConfirm={handleConfirmInitiated}
loading={isLoading}
>
<p>
<T id={'warehouse_transfer.alert.are_you_sure_you_want_to_initate'} />
</p>
</Alert>
);
}
export default compose(
withAlertStoreConnect(),
withAlertActions,
)(WarehouseTransferInitiateAlert);

View File

@@ -79,6 +79,10 @@ export const handleCashFlowTransactionType = (reference, openDrawer) => {
return openDrawer('refund-vendor-detail-drawer', { return openDrawer('refund-vendor-detail-drawer', {
refundTransactionId: reference.reference_id, refundTransactionId: reference.reference_id,
}); });
case 'InventoryAdjustment':
return openDrawer('inventory-adjustment-drawer', {
inventoryId: reference.reference_id,
});
default: default:
return openDrawer('cashflow-transaction-drawer', { return openDrawer('cashflow-transaction-drawer', {

View File

@@ -16,6 +16,9 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions'; import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions';
import { AccountDialogAction } from '../../Dialogs/AccountDialog/utils';
import { ACCOUNT_TYPE } from '../../../common';
import { compose } from 'utils'; import { compose } from 'utils';
/** /**
@@ -37,15 +40,15 @@ function CashFlowAccountsActionsBar({
// Handle add bank account. // Handle add bank account.
const handleAddBankAccount = () => { const handleAddBankAccount = () => {
openDialog('account-form', { openDialog('account-form', {
action: 'NEW_ACCOUNT_DEFINED_TYPE', action: AccountDialogAction.NewDefinedType,
accountType: 'cash', accountType: ACCOUNT_TYPE.CASH,
}); });
}; };
// Handle add cash account. // Handle add cash account.
const handleAddCashAccount = () => { const handleAddCashAccount = () => {
openDialog('account-form', { openDialog('account-form', {
action: 'NEW_ACCOUNT_DEFINED_TYPE', action: AccountDialogAction.NewDefinedType,
accountType: 'bank', accountType: ACCOUNT_TYPE.BANK,
}); });
}; };
// Handle inactive switch changing. // Handle inactive switch changing.

View File

@@ -3,32 +3,33 @@ import classNames from 'classnames';
import { FormGroup, Position, Classes, ControlGroup } from '@blueprintjs/core'; import { FormGroup, Position, Classes, ControlGroup } from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { FFormGroup } from '../../../components/Forms';
import moment from 'moment'; import moment from 'moment';
import { Features } from 'common';
import { import {
MoneyInputGroup, MoneyInputGroup,
InputPrependText, InputPrependText,
CurrencySelectList, CurrencySelectList,
BranchSelect,
BranchSelectButton,
FeatureCan,
Row, Row,
Col, Col,
} from 'components'; } from 'components';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { useCustomerFormContext } from './CustomerFormProvider'; import { useCustomerFormContext } from './CustomerFormProvider';
import { useSetPrimaryBranchToForm } from './utils';
import { import { momentFormatter, tansformDateValue, inputIntent } from 'utils';
momentFormatter,
tansformDateValue,
inputIntent,
} from 'utils';
/** /**
* Customer financial panel. * Customer financial panel.
*/ */
export default function CustomerFinancialPanel() { export default function CustomerFinancialPanel() {
const { const { currencies, customerId, branches } = useCustomerFormContext();
currencies,
customerId // Sets the primary branch to form.
} = useCustomerFormContext(); useSetPrimaryBranchToForm();
return ( return (
<div className={'tab-panel--financial'}> <div className={'tab-panel--financial'}>
@@ -62,12 +63,7 @@ export default function CustomerFinancialPanel() {
{/*------------ Opening balance -----------*/} {/*------------ Opening balance -----------*/}
<FastField name={'opening_balance'}> <FastField name={'opening_balance'}>
{({ {({ form, field, field: { value }, meta: { error, touched } }) => (
form,
field,
field: { value },
meta: { error, touched },
}) => (
<FormGroup <FormGroup
label={<T id={'opening_balance'} />} label={<T id={'opening_balance'} />}
className={classNames( className={classNames(
@@ -92,6 +88,23 @@ export default function CustomerFinancialPanel() {
)} )}
</FastField> </FastField>
{/*------------ Opening branch -----------*/}
<FeatureCan feature={Features.Branches}>
<FFormGroup
label={<T id={'customer.label.opening_branch'} />}
name={'opening_balance_branch_id'}
inline={true}
className={classNames('form-group--select-list', Classes.FILL)}
>
<BranchSelect
name={'opening_balance_branch_id'}
branches={branches}
input={BranchSelectButton}
popoverProps={{ minimal: true }}
/>
</FFormGroup>
</FeatureCan>
{/*------------ Currency -----------*/} {/*------------ Currency -----------*/}
<FastField name={'currency_code'}> <FastField name={'currency_code'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (

View File

@@ -42,6 +42,7 @@ const Schema = Yup.object().shape({
opening_balance: Yup.number().nullable(), opening_balance: Yup.number().nullable(),
currency_code: Yup.string(), currency_code: Yup.string(),
opening_balance_at: Yup.date(), opening_balance_at: Yup.date(),
opening_balance_branch_id: Yup.string(),
}); });
export const CreateCustomerForm = Schema; export const CreateCustomerForm = Schema;

View File

@@ -6,15 +6,21 @@ import {
useCreateCustomer, useCreateCustomer,
useEditCustomer, useEditCustomer,
useContact, useContact,
useBranches,
} from 'hooks/query'; } from 'hooks/query';
import { Features } from 'common';
import { useFeatureCan } from 'hooks/state';
const CustomerFormContext = createContext(); const CustomerFormContext = createContext();
function CustomerFormProvider({ customerId, ...props }) { function CustomerFormProvider({ query, customerId, ...props }) {
const { state } = useLocation(); const { state } = useLocation();
const contactId = state?.action; const contactId = state?.action;
// Features guard.
const { featureCan } = useFeatureCan();
const isBranchFeatureCan = featureCan(Features.Branches);
// Handle fetch customer details. // Handle fetch customer details.
const { data: customer, isLoading: isCustomerLoading } = useCustomer( const { data: customer, isLoading: isCustomerLoading } = useCustomer(
customerId, customerId,
@@ -28,6 +34,13 @@ function CustomerFormProvider({ customerId, ...props }) {
// Handle fetch Currencies data table // Handle fetch Currencies data table
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
// Fetches the branches list.
const {
data: branches,
isLoading: isBranchesLoading,
isSuccess: isBranchesSuccess,
} = useBranches(query, { enabled: isBranchFeatureCan });
// Form submit payload. // Form submit payload.
const [submitPayload, setSubmitPayload] = useState({}); const [submitPayload, setSubmitPayload] = useState({});
@@ -38,18 +51,20 @@ function CustomerFormProvider({ customerId, ...props }) {
const isNewMode = contactId || !customerId; const isNewMode = contactId || !customerId;
const isFormLoading = const isFormLoading =
isCustomerLoading || isCurrenciesLoading || isContactLoading; isCustomerLoading || isCurrenciesLoading || isBranchesLoading;
const provider = { const provider = {
customerId, customerId,
customer, customer,
currencies, currencies,
branches,
contactDuplicate, contactDuplicate,
submitPayload, submitPayload,
isNewMode, isNewMode,
isCustomerLoading, isCustomerLoading,
isCurrenciesLoading, isCurrenciesLoading,
isBranchesSuccess,
isFormLoading, isFormLoading,
setSubmitPayload, setSubmitPayload,

View File

@@ -1,5 +1,9 @@
import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { useFormikContext } from 'formik';
import { first } from 'lodash';
import { useCustomerFormContext } from './CustomerFormProvider';
export const defaultInitialValues = { export const defaultInitialValues = {
customer_type: 'business', customer_type: 'business',
@@ -35,4 +39,20 @@ export const defaultInitialValues = {
opening_balance: '', opening_balance: '',
currency_code: '', currency_code: '',
opening_balance_at: moment(new Date()).format('YYYY-MM-DD'), opening_balance_at: moment(new Date()).format('YYYY-MM-DD'),
opening_balance_branch_id: '',
};
export const useSetPrimaryBranchToForm = () => {
const { setFieldValue } = useFormikContext();
const { branches, isBranchesSuccess } = useCustomerFormContext();
React.useEffect(() => {
if (isBranchesSuccess) {
const primaryBranch = branches.find((b) => b.primary) || first(branches);
if (primaryBranch) {
setFieldValue('opening_balance_branch_id', primaryBranch.id);
}
}
}, [isBranchesSuccess, setFieldValue, branches]);
}; };

View File

@@ -5,21 +5,9 @@ import AccountDialogForm from './AccountDialogForm';
/** /**
* Account dialog content. * Account dialog content.
*/ */
export default function AccountDialogContent({ export default function AccountDialogContent({ dialogName, payload }) {
dialogName,
accountId,
action,
parentAccountId,
accountType,
}) {
return ( return (
<AccountDialogProvider <AccountDialogProvider dialogName={dialogName} payload={payload}>
dialogName={dialogName}
accountId={accountId}
action={action}
parentAccountId={parentAccountId}
accountType={accountType}
>
<AccountDialogForm /> <AccountDialogForm />
</AccountDialogProvider> </AccountDialogProvider>
); );

View File

@@ -25,6 +25,7 @@ const defaultInitialValues = {
name: '', name: '',
code: '', code: '',
description: '', description: '',
currency_code:'',
subaccount: false, subaccount: false,
}; };
@@ -42,9 +43,7 @@ function AccountFormDialogContent({
account, account,
accountId, accountId,
action, payload,
parentAccountId,
accountType,
isNewMode, isNewMode,
dialogName, dialogName,
} = useAccountDialogContext(); } = useAccountDialogContext();
@@ -100,7 +99,6 @@ function AccountFormDialogContent({
.catch(handleError); .catch(handleError);
} }
}; };
// Form initial values in create and edit mode. // Form initial values in create and edit mode.
const initialValues = { const initialValues = {
...defaultInitialValues, ...defaultInitialValues,
@@ -110,11 +108,7 @@ function AccountFormDialogContent({
* as well. * as well.
*/ */
...transformToForm( ...transformToForm(
transformAccountToForm(account, { transformAccountToForm(account, payload),
action,
parentAccountId,
accountType,
}),
defaultInitialValues, defaultInitialValues,
), ),
}; };
@@ -132,7 +126,7 @@ function AccountFormDialogContent({
> >
<AccountDialogFormContent <AccountDialogFormContent
dialogName={dialogName} dialogName={dialogName}
action={action} action={payload?.action}
onClose={handleClose} onClose={handleClose}
/> />
</Formik> </Formik>

View File

@@ -17,12 +17,14 @@ import {
Hint, Hint,
AccountsSelectList, AccountsSelectList,
AccountsTypesSelect, AccountsTypesSelect,
CurrencySelect,
} from 'components'; } from 'components';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
import { inputIntent } from 'utils'; import { inputIntent } from 'utils';
import { compose } from 'redux'; import { compose } from 'redux';
import { useAutofocus } from 'hooks'; import { useAutofocus } from 'hooks';
import { FOREIGN_CURRENCY_ACCOUNTS } from '../../../common/accountTypes';
import { useAccountDialogContext } from './AccountDialogProvider'; import { useAccountDialogContext } from './AccountDialogProvider';
/** /**
@@ -37,7 +39,8 @@ function AccountFormDialogFields({
const accountNameFieldRef = useAutofocus(); const accountNameFieldRef = useAutofocus();
// Account form context. // Account form context.
const { accounts, accountsTypes } = useAccountDialogContext(); const { fieldsDisabled, accounts, accountsTypes, currencies } =
useAccountDialogContext();
return ( return (
<Form> <Form>
@@ -58,12 +61,9 @@ function AccountFormDialogFields({
defaultSelectText={<T id={'select_account_type'} />} defaultSelectText={<T id={'select_account_type'} />}
onTypeSelected={(accountType) => { onTypeSelected={(accountType) => {
form.setFieldValue('account_type', accountType.key); form.setFieldValue('account_type', accountType.key);
form.setFieldValue('currency_code', '');
}} }}
disabled={ disabled={fieldsDisabled.accountType}
action === 'edit' ||
action === 'new_child' ||
action === 'NEW_ACCOUNT_DEFINED_TYPE'
}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
popoverFill={true} popoverFill={true}
/> />
@@ -143,6 +143,7 @@ function AccountFormDialogFields({
)} )}
inline={true} inline={true}
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="parent_account_id" />}
> >
<AccountsSelectList <AccountsSelectList
accounts={accounts} accounts={accounts}
@@ -159,6 +160,24 @@ function AccountFormDialogFields({
</FastField> </FastField>
</If> </If>
<If condition={FOREIGN_CURRENCY_ACCOUNTS.includes(values.account_type)}>
{/*------------ Currency -----------*/}
<FastField name={'currency_code'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'currency'} />}
className={classNames('form-group--select-list', Classes.FILL)}
inline={true}
>
<CurrencySelect
name={'currency_code'}
currencies={currencies}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</FastField>
</If>
<FastField name={'description'}> <FastField name={'description'}>
{({ field, meta: { error, touched } }) => ( {({ field, meta: { error, touched } }) => (
<FormGroup <FormGroup
@@ -187,7 +206,7 @@ function AccountFormDialogFields({
<Button <Button
intent={Intent.PRIMARY} intent={Intent.PRIMARY}
loading={isSubmitting} loading={isSubmitting}
style={{ minWidth: '75px' }} style={{ minWidth: '95px' }}
type="submit" type="submit"
> >
{action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />} {action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />}

View File

@@ -3,25 +3,19 @@ import { DialogContent } from 'components';
import { import {
useCreateAccount, useCreateAccount,
useAccountsTypes, useAccountsTypes,
useCurrencies,
useAccount, useAccount,
useAccounts, useAccounts,
useEditAccount, useEditAccount,
} from 'hooks/query'; } from 'hooks/query';
import { AccountDialogAction, getDisabledFormFields } from './utils';
const AccountDialogContext = createContext(); const AccountDialogContext = createContext();
/** /**
* Account form provider. * Account form provider.
*/ */
function AccountDialogProvider({ function AccountDialogProvider({ dialogName, payload, ...props }) {
accountId,
parentAccountId,
action,
accountType,
dialogName,
...props
}) {
// Create and edit account mutations. // Create and edit account mutations.
const { mutateAsync: createAccountMutate } = useCreateAccount(); const { mutateAsync: createAccountMutate } = useCreateAccount();
const { mutateAsync: editAccountMutate } = useEditAccount(); const { mutateAsync: editAccountMutate } = useEditAccount();
@@ -30,25 +24,36 @@ function AccountDialogProvider({
const { data: accounts, isLoading: isAccountsLoading } = useAccounts(); const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
// Fetches accounts types. // Fetches accounts types.
const { const { data: accountsTypes, isLoading: isAccountsTypesLoading } =
data: accountsTypes, useAccountsTypes();
isLoading: isAccountsTypesLoading,
} = useAccountsTypes();
// Fetches the specific account details. // Fetches the specific account details.
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, { const { data: account, isLoading: isAccountLoading } = useAccount(
enabled: !!accountId, payload.accountId,
}); {
enabled:
!!payload.accountId && payload.action === AccountDialogAction.Edit,
},
);
const isNewMode = !accountId; // Handle fetch Currencies data table
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
const isNewMode = !payload?.action;
// Retrieves the disabled fields of the form.
const fieldsDisabled = React.useMemo(
() => getDisabledFormFields(account, payload),
[account, payload],
);
// Provider payload. // Provider payload.
const provider = { const provider = {
dialogName, dialogName,
accountId, payload,
parentAccountId, fieldsDisabled,
action,
accountType, currencies,
createAccountMutate, createAccountMutate,
editAccountMutate, editAccountMutate,
@@ -57,11 +62,15 @@ function AccountDialogProvider({
account, account,
isAccountsLoading, isAccountsLoading,
isNewMode isCurrenciesLoading,
isNewMode,
}; };
const isLoading = const isLoading =
isAccountsLoading || isAccountsTypesLoading || isAccountLoading; isAccountsLoading ||
isAccountsTypesLoading ||
isAccountLoading ||
isCurrenciesLoading;
return ( return (
<DialogContent isLoading={isLoading}> <DialogContent isLoading={isLoading}>

View File

@@ -18,9 +18,11 @@ function AccountFormDialog({
<Dialog <Dialog
name={dialogName} name={dialogName}
title={ title={
(payload.action === 'edit') ? payload.action === 'edit' ? (
(<T id={'edit_account'} />) : <T id={'edit_account'} />
(<T id={'new_account'} />) ) : (
<T id={'new_account'} />
)
} }
className={'dialog--account-form'} className={'dialog--account-form'}
autoFocus={true} autoFocus={true}
@@ -28,18 +30,10 @@ function AccountFormDialog({
isOpen={isOpen} isOpen={isOpen}
> >
<DialogSuspense> <DialogSuspense>
<AccountDialogContent <AccountDialogContent dialogName={dialogName} payload={payload} />
dialogName={dialogName}
accountId={payload.id}
action={payload.action}
parentAccountId={payload.parentAccountId}
accountType={payload.accountType}
/>
</DialogSuspense> </DialogSuspense>
</Dialog> </Dialog>
); );
} }
export default compose( export default compose(withDialogRedux())(AccountFormDialog);
withDialogRedux(),
)(AccountFormDialog);

Some files were not shown because too many files have changed in this diff Show More