Compare commits

...

272 Commits

Author SHA1 Message Date
Ankush Menat
28ce2958fa ci: Add fake passing tests when CI is skipped 2024-01-25 14:14:25 +05:30
ruthra kumar
4f215f1b70 Merge pull request #38218 from rtdany10/account-balance-mismatch
fix: honour currency precision while fetching balance
2024-01-25 12:28:36 +05:30
rohitwaghchaure
c0a1188067 Merge pull request #39547 from rohitwaghchaure/fixed-item-tax-template-not-working-for-e-commerce
fix: Item Tax template is not working for e-commerce
2024-01-25 11:36:48 +05:30
Nabin Hait
ca02dfa652 Merge pull request #39498 from nabinhait/asset-cancellation-fix
fix: cancellation of asset/asset capitalization
2024-01-25 11:36:19 +05:30
Rohit Waghchaure
7d3240ae3a fix: Item Tax template is not working for e-commerce 2024-01-25 11:08:33 +05:30
ruthra kumar
93681cfa24 Merge branch 'develop' into pr/38218 2024-01-25 09:58:54 +05:30
ruthra kumar
4f1e729b7c Merge pull request #39331 from FHenry/dev_fix_payment_terms_status_for_sales_order_report
fix: Payment Terms Status for Sales Order report show all payment terms from orders (not only when there is a payment terms template)
2024-01-24 16:11:52 +05:30
ruthra kumar
735576ab27 Merge branch 'develop' into dev_fix_payment_terms_status_for_sales_order_report 2024-01-24 15:45:46 +05:30
rohitwaghchaure
23199a3271 Merge pull request #39389 from rohitwaghchaure/fixed-incorrect-active-serial-nos
fix: incorrect active serial nos
2024-01-24 15:36:31 +05:30
Rohit Waghchaure
64cb1153de fix: incorrect active serial nos 2024-01-24 15:15:50 +05:30
ruthra kumar
4a4c4ba21b Merge pull request #39529 from ruthra-kumar/typeerror_on_company_transaction_deletion
fix: AttributeError in company transaction deletion
2024-01-24 13:09:49 +05:30
rohitwaghchaure
a552df8a9f Merge pull request #39525 from rohitwaghchaure/fixed-auto-mr-email-with-user-permissions-issue
fix: email list for auto reorder material request
2024-01-24 12:35:35 +05:30
ruthra kumar
b127aa308e fix: AttributeError in company transaction deletion 2024-01-24 12:24:02 +05:30
rohitwaghchaure
02028becb3 Merge pull request #39521 from rohitwaghchaure/fixed-not-able-to-edit-adddress
fix: not able to edit address through portal
2024-01-24 11:50:02 +05:30
Rohit Waghchaure
764f3422a0 fix: email list for auto reorder material request 2024-01-24 11:45:15 +05:30
Deepesh Garg
236c7e1e95 Merge pull request #39493 from GursheenK/skip-liability-acc-for-internal-transfers
fix: skip setting liability account for internal transfer
2024-01-24 10:34:19 +05:30
Deepesh Garg
9f1ddeb4e4 Merge pull request #39520 from barredterra/fix-typos
fix: typos
2024-01-24 10:33:27 +05:30
Rohit Waghchaure
b046d980ad fix: not able to edit address through portal 2024-01-24 10:29:55 +05:30
barredterra
806696a003 fix: typos 2024-01-24 02:59:52 +01:00
Raffael Meyer
7a6a789199 Merge pull request #39512 from barredterra/refactor-split-batch 2024-01-23 17:54:28 +01:00
barredterra
7a7a213285 refactor(Batch): use const instead of var 2024-01-23 15:02:42 +01:00
barredterra
34ec2f8a2b fix(Batch): reload doc after splitting
to show updated qty
2024-01-23 14:57:23 +01:00
rohitwaghchaure
4832175341 Merge pull request #39503 from rohitwaghchaure/fixed-serial-no-ledger-permission
fix: Serial No Ledger permission issue
2024-01-23 19:06:40 +05:30
barredterra
3c7e7a76f0 refactor: split batch 2024-01-23 14:23:32 +01:00
ruthra kumar
ebaa5d3add Merge pull request #39054 from ruthra-kumar/provision_to_set_dimension_in_reconciliation_tool
refactor: provision to filter on dimensions in reconciliation tool
2024-01-23 17:28:21 +05:30
ruthra kumar
0d7dd93284 Merge pull request #38560 from blaggacao/feat/so-po-advance-payment-status
feat!: advance payment status on advance payment doctypes
2024-01-23 16:39:22 +05:30
ruthra kumar
9b4e757b0b test: advance payment status for Purchase Order 2024-01-23 15:53:05 +05:30
ruthra kumar
8de03ef836 test: advance payment status for Sales Order 2024-01-23 15:50:52 +05:30
David Arnold
bd6a4ca1d7 fix: move value initialization to ensure it is commited 2024-01-23 10:30:09 +01:00
David Arnold
7d8aa469d7 fix: align with 'Partly/Fully X' nomenclature in so & po 2024-01-23 10:30:08 +01:00
David Arnold
b1aef01a1f fix: always update the advance payment status 2024-01-23 10:30:08 +01:00
David Arnold
c88ce55242 fix: advance payment doctypes to keep input/output distinction 2024-01-23 10:30:07 +01:00
Rohit Waghchaure
1a670ff266 fix: Serial No Ledger permission issue 2024-01-23 13:27:37 +05:30
Nabin Hait
1a686cb66d fix: Use db_set to set a value in on_cancel 2024-01-23 12:46:15 +05:30
Nabin Hait
31592b8f3a fix: cancellation of asset/asset capitalization 2024-01-23 12:42:54 +05:30
rohitwaghchaure
f8675817e2 Merge pull request #39478 from rohitwaghchaure/fixed-ux-improvement-for-SABB
fix: UX improvements for Serial and Batch Bundle
2024-01-23 11:57:03 +05:30
Gursheen Anand
236b73565e fix: skip liability account for internal transfer 2024-01-22 21:13:32 +05:30
ruthra kumar
72614fe9e1 Merge branch 'develop' into pr/38560 2024-01-22 17:26:35 +05:30
rohitwaghchaure
60809ced85 Merge pull request #39488 from rohitwaghchaure/fixed-validate-stock-uom-integer-value
fix: UOM needs to be whole number not being checked in quotations
2024-01-22 17:24:32 +05:30
Rohit Waghchaure
aaf83da3e9 fix: UOM needs to be whole number not being checked in quotations 2024-01-22 16:43:54 +05:30
ruthra kumar
4c20a4710b Merge pull request #39484 from ruthra-kumar/move_project_filter_to_common
refactor: move 'project' set_query to sales_common.js
2024-01-22 15:50:17 +05:30
ruthra kumar
52814724eb refactor: move 'project' set_query to sales_common.js 2024-01-22 15:32:16 +05:30
Rohit Waghchaure
fc0d2aeeff fix: auto create serial no on scan 2024-01-22 13:42:33 +05:30
ruthra kumar
7c2cb70387 refactor: handle dynamic dimension in order query 2024-01-22 12:06:07 +05:30
ruthra kumar
ec0f17ca8b refactor: update dimensions, only if provided 2024-01-22 11:59:20 +05:30
ruthra kumar
f8bbb0619c refactor: dynamic dimension filters in pop up 2024-01-22 10:43:09 +05:30
ruthra kumar
b17e632a85 Merge pull request #39457 from ruthra-kumar/background_job_transaction_deletion
refactor: delete transactions in background
2024-01-22 09:57:25 +05:30
Deepesh Garg
6d8949adea Merge pull request #39462 from GursheenK/pdf-party-ap-ar
fix: party field in PDF for AP / AR reports
2024-01-22 09:31:34 +05:30
rohitwaghchaure
faab225126 Merge pull request #39476 from rohitwaghchaure/fixed-added-button-to-create-serial-batch-from-PI
fix: added button to make serial / batch from Purchase Invoice
2024-01-21 22:22:42 +05:30
Rohit Waghchaure
63ffce58cc test: fixed test 2024-01-21 20:59:38 +05:30
Rohit Waghchaure
5d94f0bde5 fix: UX improvements for Serial and Batch Bundle 2024-01-21 20:46:57 +05:30
Rohit Waghchaure
b4393bc03d fix: added button to make serial / batch from Purchase Invoice 2024-01-21 20:17:15 +05:30
rohitwaghchaure
da0ad3bc00 Merge pull request #39475 from rohitwaghchaure/fixed-key-error-during-reposting
fix: key error during reposting
2024-01-21 19:51:43 +05:30
David Arnold
9fc5c0cc58 Merge remote-tracking branch 'origin/develop' into feat/so-po-advance-payment-status 2024-01-21 15:16:13 +01:00
Rohit Waghchaure
ebc8230d45 fix: key error during reposting 2024-01-21 18:05:20 +05:30
Gursheen Kaur Anand
273bc1b1e3 Merge pull request #39229 from blaggacao/fix/tds-report
fix: use most reliable section reference per report line
2024-01-21 13:39:38 +05:30
Gursheen Kaur Anand
c40719caa5 Merge pull request #39424 from frappe/revert-38556-period-end-date-for-financial-statements
Revert "fix(minor): financial statements period end date"
2024-01-20 17:57:46 +05:30
Gursheen Anand
b2d9380596 fix: party field in pdf html 2024-01-19 17:08:02 +05:30
ruthra kumar
fcf4687c52 test: dimension inheritance on adv allocation 2024-01-19 16:50:54 +05:30
ruthra kumar
cbd443a78a refactor: pass dimensions on advance allocation 2024-01-19 16:44:59 +05:30
ruthra kumar
6148fb024b test: dimension inheritance in PE reconciliation 2024-01-19 15:57:13 +05:30
Gursheen Kaur Anand
9678d050a4 Merge pull request #39426 from GursheenK/insufficient-permissions-for-manager
fix: FY permission for accounts and stock managers
2024-01-19 11:54:20 +05:30
ruthra kumar
a50808a077 refactor: delete transactions in background 2024-01-19 11:43:08 +05:30
Gursheen Anand
125847c69f Merge branch 'develop' into revert-38556-period-end-date-for-financial-statements 2024-01-19 11:40:50 +05:30
Gursheen Kaur Anand
4ca63c07f6 Merge branch 'frappe:develop' into insufficient-permissions-for-manager 2024-01-19 11:19:32 +05:30
Rucha Mahabal
35067282cf refactor(UX): Accounts workspace cleanup (#39232)
* refactor(UX): Accounts workspace cleanup

* chore: move asset workspace outside accounting

* fix: remove redundant links from parent workspace

* chore: change icons for payable & receivable workspaces

* chore: remove redundant links from subworkspaces
2024-01-19 11:13:09 +05:30
ruthra kumar
c44eb432a5 refactor: pass dimension values to Gain/Loss journal 2024-01-18 16:42:22 +05:30
Gursheen Kaur Anand
871a1f4565 Merge pull request #39449 from GursheenK/payment-entry-unallocated-amount-after-taxes
fix: unallocated amount after taxes and charges
2024-01-18 16:13:31 +05:30
Gursheen Anand
99b94af49f fix: linting issue 2024-01-18 15:05:19 +05:30
Gursheen Anand
e9bc63aacf fix: set unallocated amount after base tax 2024-01-18 14:33:10 +05:30
ruthra kumar
ba5a7c8cd8 test: dimension inheritance for cr note reconciliation 2024-01-18 13:29:33 +05:30
Ankush Menat
ef7aefeb45 ci: split pre-commit and semgrep jobs (#39445) 2024-01-18 11:29:53 +05:30
rohitwaghchaure
45aea56198 Merge pull request #39436 from rohitwaghchaure/fixed-duplicate-name-error-for-variant-creation
fix: duplicate name error while making variant
2024-01-18 06:50:50 +05:30
Nabin Hait
daf954057f Merge pull request #39429 from nabinhait/composite-asset-using-asset
fix: composite asset capitalization using asset components
2024-01-17 21:04:49 +05:30
Rohit Waghchaure
d7e6b83e64 fix: duplicate name error while making variant 2024-01-17 20:52:16 +05:30
rohitwaghchaure
80dc5a7b1c Merge pull request #39433 from FHenry/dev_better_display_item_BomCreator
refactor: BOM creator item selector with short description
2024-01-17 20:28:50 +05:30
Florian HENRY
0f881bc90a refactor: BOM creator item selector with short description 2024-01-17 13:37:22 +01:00
mergify[bot]
6efa92de70 Merge branch 'develop' into composite-asset-using-asset 2024-01-17 12:20:05 +00:00
Nabin Hait
2adb710751 Merge pull request #39427 from nabinhait/test-fix333
fix: Asset module tests
2024-01-17 17:21:47 +05:30
Nabin Hait
97f69986ff fix: Asset module tests 2024-01-17 16:39:39 +05:30
Nabin Hait
5df40661d2 fix: composite asset capitalization using asset components 2024-01-17 16:17:53 +05:30
Deepesh Garg
889d67bcee Merge pull request #39367 from deepeshgarg007/revert_dynamic_splitting
Revert dynamic splitting
2024-01-17 15:03:13 +05:30
Gursheen Anand
8b91287034 fix: account and stock manager read perm 2024-01-17 13:09:51 +05:30
Deepesh Garg
1148ed1566 Merge pull request #39423 from deepeshgarg007/fix_subscription_period_update
fix: Update subscription period
2024-01-17 12:57:40 +05:30
ruthra kumar
e3c44231ab chore: test dimension filter output 2024-01-17 12:51:44 +05:30
ruthra kumar
188ff8cde7 refactor: apply dimension filters on cr/dr notes 2024-01-17 12:51:41 +05:30
Deepesh Garg
3aa17fa0d6 chore: freezing date check 2024-01-17 12:47:27 +05:30
Deepesh Garg
4f3aeaefc1 chore: Remove unwanted changes 2024-01-17 12:42:22 +05:30
Deepesh Garg
120bfdf33d Merge branch 'develop' of https://github.com/frappe/erpnext into revert_dynamic_splitting 2024-01-17 12:33:07 +05:30
Gursheen Kaur Anand
73625a2622 Revert "fix(minor): financial statements period end date" 2024-01-17 12:25:03 +05:30
Nabin Hait
9f2b62dd1c Merge pull request #39386 from nabinhait/asset-capitalisation-calcellation
fix: Cancel asset capitalisation record on cancellation of asset and vice-versa
2024-01-17 12:14:15 +05:30
Nabin Hait
60f52adc90 Merge pull request #39385 from nabinhait/wdv-as-per-income-tax-act
fix: WDV as per IT Act: calculate yearly amount first and then split it based on months
2024-01-17 12:13:23 +05:30
Deepesh Garg
7eefedfb11 fix: Update subscription period 2024-01-17 10:57:19 +05:30
HENRY Florian
af80d253db fix: consistency in display reserved_stock checkbox on Sales Order Item according global settings and item.is_stock_item (#38322)
* fix: consistency in display reserved_stock checkbox on Sales Order Item according global settings and item.is_stock_item

* fix: evaluate depends_on for fdata visibility in grid

* fix: evaluate depends_on for fdata visibility in grid

* chore: change after review

* chore: change for review
2024-01-17 10:43:36 +05:30
ruthra kumar
ab939cc6e8 refactor: Credit Note and its Exc gain/loss JE inherits dimensions 2024-01-16 16:48:50 +05:30
ruthra kumar
ca9413bc64 Merge pull request #39402 from ruthra-kumar/fix_project_query
fix: project query controller logic
2024-01-16 16:24:02 +05:30
ruthra kumar
bfe42fdccb refactor: better ordering of query result 2024-01-16 15:58:19 +05:30
rohitwaghchaure
ce2dd28a25 Merge pull request #39406 from rohitwaghchaure/fixed-bin-permission-issue
fix: permission issue for the Bin
2024-01-16 15:50:46 +05:30
Deepesh Garg
96dcfba65a Merge branch 'develop' of https://github.com/frappe/erpnext into revert_dynamic_splitting 2024-01-16 15:42:02 +05:30
Rohit Waghchaure
6e4d4a55cd fix: permission issue for the BIN 2024-01-16 15:12:28 +05:30
ruthra kumar
3349dde5e2 fix(test): test case for project query 2024-01-16 14:28:09 +05:30
ruthra kumar
4eefb445a7 fix: project query controller logic 2024-01-16 13:38:53 +05:30
Ankush Menat
ed927f102e perf: use unbuffered_cursor for stock_ageing report (#39399)
perf: use unbuffered_cursor for stock stock_ageing report

Unbuffered cursor lets us load one row at a time in memory from mysql instead of lowing all at once.

This makes it possible to run the report for large number of SLEs.
2024-01-16 11:43:35 +05:30
ruthra kumar
82026f780d Merge pull request #39400 from ruthra-kumar/fix_broken_subscription_test
fix: broken multi currency test case in subscription
2024-01-16 11:39:42 +05:30
ruthra kumar
e5aeab7e7e fix: broken multi currency test case in subscription 2024-01-16 11:16:39 +05:30
Deepesh Garg
32738637ce Merge pull request #39394 from noec764/Fix_UntranslatedColumnsInGlobalLedger
fix: Untranslated columns in Global Ledger Report
2024-01-16 11:03:47 +05:30
Alexandre Lumertz Damiani
80f5026208 fix: translate (#39395) 2024-01-16 10:46:00 +05:30
Alexandre Lumertz Damiani
00619342e1 fix: translate (#39396) 2024-01-16 10:44:59 +05:30
Alexandre Lumertz Damiani
b719585a2f fix: translate (#39397) 2024-01-16 10:44:17 +05:30
Alexandre Lumertz Damiani
4970b5d5bc fix: translate (#39398) 2024-01-16 10:43:33 +05:30
Noé
bdd382bdfd fix: Untranslated columns in Global Ledger 2024-01-15 16:40:45 +01:00
ruthra kumar
92a5cda61a Merge pull request #39391 from ruthra-kumar/multiple_typeerror_fixes
fix: possible typerror in utils.js
2024-01-15 20:45:27 +05:30
ruthra kumar
60b26ad8b2 fix: possible typerror in utils.js
and remove unwanted debugging statements
2024-01-15 20:37:21 +05:30
Nabin Hait
efe9f6656f fix: Cancel asset capitalisation record on cancellation of asset and vice-versa 2024-01-15 17:54:47 +05:30
Nabin Hait
22bd6a54b2 fix: WDV as per IT Act: calculate yearly amount first and then split it based on months 2024-01-15 16:54:19 +05:30
Deepesh Garg
a36b6cb102 Merge pull request #39384 from deepeshgarg007/income_account_filter
feat: Income account filter in item-wise reports
2024-01-15 16:52:39 +05:30
Deepesh Garg
d91813c277 feat: Income account filter in item-wise reports 2024-01-15 16:50:14 +05:30
ruthra kumar
0ec17590ae fix: typo's and parameter changes 2024-01-15 16:17:33 +05:30
ruthra kumar
2154502955 refactor: partial change on outstanding invoice popup 2024-01-15 16:17:33 +05:30
ruthra kumar
a4ddf93492 Merge pull request #39332 from ruthra-kumar/validate_subscription_billing_currency
refactor: prevent foreign currency subscription for a party
2024-01-15 15:05:31 +05:30
ruthra kumar
9c5a79209e refactor: replace sql with query builder for Jourals query 2024-01-15 14:55:15 +05:30
ruthra kumar
5dc22e1811 refactor: pass dimension details to query 2024-01-15 14:55:15 +05:30
ruthra kumar
ad8475cb8b refactor: set query filters for dimensions 2024-01-15 14:55:15 +05:30
ruthra kumar
ff60ec85b8 refactor: pass dimension filters to query 2024-01-15 14:55:15 +05:30
ruthra kumar
c1fe4bcc64 refactor: handle dimension filters 2024-01-15 14:55:15 +05:30
ruthra kumar
20576e0f47 refactor: column break in dimension section 2024-01-15 14:55:15 +05:30
ruthra kumar
20e0acc20a refactor: dimensions filter section in payment reconciliation 2024-01-15 14:55:15 +05:30
ruthra kumar
cfb3d87267 refactor: update dimension doctypes in hooks 2024-01-15 14:55:15 +05:30
ruthra kumar
1cde804c77 refactor: dimensions section in allocation table in reconciliation 2024-01-15 14:55:15 +05:30
ruthra kumar
1387b0ba7f refactor(test): supply default currency for subscription plans 2024-01-15 14:42:57 +05:30
Ankush Menat
2e03af7ac4 perf: use iterator for stock ageing report (#39346) 2024-01-15 14:35:28 +05:30
s-aga-r
749c735627 Merge pull request #39377 from s-aga-r/BUMP-NODE
ci: bump node in release workflow
2024-01-15 11:58:51 +05:30
s-aga-r
aef87cced7 ci: bump node in release workflow 2024-01-15 11:54:26 +05:30
ruthra kumar
6bb2d9195f Merge pull request #39336 from ruthra-kumar/better_validation_on_bank_transaction
refactor: disallow bank transactions on different currencies
2024-01-15 10:01:50 +05:30
ruthra kumar
28ebc4cfee Merge pull request #39371 from ruthra-kumar/fix_customer_ledger_summary_report
fix: incorrect sql error if account name has '%'
2024-01-15 09:38:50 +05:30
rohitwaghchaure
ad5906916d Merge pull request #39372 from rohitwaghchaure/fixed-get-query-for-batch-no-field
fix: batches not coming correctly in the batch selector
2024-01-14 23:48:48 +05:30
Rohit Waghchaure
114f2b4326 fix: batches not coming correctly in the batch selector 2024-01-14 23:27:29 +05:30
ruthra kumar
a27a4db3de refactor(test): supply default currency to Bank Transaction 2024-01-14 18:09:19 +05:30
ruthra kumar
b4354cbc8d refactor: better error message 2024-01-14 18:04:15 +05:30
Deepesh Garg
02fde73545 fix: Against account variable 2024-01-14 18:01:44 +05:30
ruthra kumar
19975dcb7b refactor: making currency mandatory for subcscription plans 2024-01-14 17:59:43 +05:30
ruthra kumar
641c3de0ca fix: incorrect sql error if account name has '%' 2024-01-14 17:37:34 +05:30
rohitwaghchaure
cf6b52e543 Merge pull request #39224 from mahsem/patch-1
Update purchase_taxes_and_charges.json label Rate to Tax Rate
2024-01-14 11:26:35 +05:30
Deepesh Garg
9500254861 Revert "chore: orderby in gle"
This reverts commit 005c5a587f.
2024-01-14 11:25:58 +05:30
Deepesh Garg
13e5578bc6 Revert "fix: check for unmerged gle in purchase receipt test"
This reverts commit 47c78a5a73.
2024-01-14 11:25:50 +05:30
Deepesh Garg
24137ff54f Revert "fix: subcontracting receipt gle test"
This reverts commit 24ccb3eb78.
2024-01-14 11:25:39 +05:30
Deepesh Garg
9a13842751 Revert "fix: check for split entries in stock entry test"
This reverts commit a56b79cc72.
2024-01-14 11:25:30 +05:30
Deepesh Garg
13b4ddec63 Revert "fix: query for against types"
This reverts commit 262cafc430.
2024-01-14 11:25:09 +05:30
Gursheen Anand
39c8507dc2 fix: query for against types 2024-01-14 11:24:51 +05:30
Deepesh Garg
0b1cc7fad1 Revert "fix: fetch against link value in gl report"
This reverts commit 9aeb3932d0.
2024-01-14 11:24:00 +05:30
Deepesh Garg
8bc1efcf8b Revert "refactor: set against account link for jv"
This reverts commit 450c2470e9.
2024-01-14 11:23:34 +05:30
Deepesh Garg
1a67d7d95f Revert "refactor: use both fields to store against values"
This reverts commit 09439334ca.
2024-01-14 11:22:50 +05:30
Deepesh Garg
4dad4b50fb Revert "refactor: keep old against fields intact"
This reverts commit f9c88ea7bc.
2024-01-14 11:21:19 +05:30
Deepesh Garg
0f9734ae37 Revert "fix: split expected jv entries for scrap asset"
This reverts commit 291a499124.
2024-01-14 11:19:46 +05:30
Deepesh Garg
a43ee34bd5 Revert "fix: purchase receipt test"
This reverts commit 5ce395a60a.
2024-01-14 11:16:29 +05:30
Deepesh Garg
e6f599b32d Revert "fix: single dr cr entries"
This reverts commit e845b63228.
2024-01-14 11:16:17 +05:30
Deepesh Garg
8cf6ff69c0 Revert "fix: remove join for against in purchase receipt"
This reverts commit 758ec720de.
2024-01-14 11:14:14 +05:30
Deepesh Garg
2249b7c793 Revert "fix: auto separate against accounts"
This reverts commit ff0343d2cc.
2024-01-14 11:13:34 +05:30
Deepesh Garg
591de1338b Revert "fix: combine jv entries for rate revaluation"
This reverts commit 3d00d74fed.
2024-01-14 11:12:36 +05:30
Deepesh Garg
2c95cd206b Revert "fix: remove multiple against account values from gle"
This reverts commit 35d92abe73.
2024-01-14 11:12:15 +05:30
Deepesh Garg
8ee6dbc1e2 Revert "fix: make JV account against field a dynamic link"
This reverts commit aab5737ff3.
2024-01-14 11:10:22 +05:30
Deepesh Garg
beb169cf75 Revert "fix: asset capitalization tests"
This reverts commit 952e8cf60c.
2024-01-14 11:09:28 +05:30
Deepesh Garg
b40d3b0a05 Revert "fix: purchase receipt tests"
This reverts commit fcfdb9b566.
2024-01-14 11:09:18 +05:30
Deepesh Garg
93ff84bf56 Revert "fix: remove multiple accounts from against in capitalization"
This reverts commit f705bf2efe.
2024-01-14 11:06:01 +05:30
Deepesh Garg
498c9c7955 Revert "fix: set against type in asset"
This reverts commit 6e1565c32c.
2024-01-14 11:04:51 +05:30
Deepesh Garg
073f2fa302 Revert "fix: set against type in stock controller"
This reverts commit 4ea43ebc5d.
2024-01-14 11:04:40 +05:30
Deepesh Garg
9339a8b57f Revert "fix: set against type in utils"
This reverts commit f292a0cc4c.
2024-01-14 11:04:13 +05:30
Deepesh Garg
fbeaf2b398 Revert "fix: set against type in controllers"
This reverts commit 4c5a83d6cf.
2024-01-14 11:04:00 +05:30
Deepesh Garg
7c0e180fd9 Revert "fix: set against type in deferred revenue"
This reverts commit 82774f89b1.
2024-01-14 11:01:40 +05:30
Deepesh Garg
1710e10b31 Revert "fix: set against type in inv gl dict"
This reverts commit 19b220f39c.
2024-01-14 11:01:27 +05:30
Deepesh Garg
8ae7ca7f14 Revert "fix: use dynamic link for against field"
This reverts commit 725a7f90e9.
2024-01-14 10:56:17 +05:30
Deepesh Garg
5fc29ac913 Merge pull request #39366 from frappe/revert-38914-multi_currency_ledger_jv_pe
Revert "fix: GL values in transaction currency via JV"
2024-01-14 10:52:30 +05:30
Deepesh Garg
41d9225bd1 Revert "fix: GL values in transaction currency via JV" 2024-01-14 10:51:30 +05:30
Deepesh Garg
53f6cfb216 Merge pull request #39363 from frappe/revert-39248-set-against-accounts-for-backend-JVs
Revert "fix: JV GLEs for auto-set against accounts"
2024-01-14 10:51:06 +05:30
rohitwaghchaure
6827edb2c5 fix: modified date 2024-01-14 10:45:43 +05:30
rohitwaghchaure
0b525f9d87 Merge pull request #39359 from rohitwaghchaure/fixed-added-field-item-group-in-stock-reco
fix: added item group in stock reco
2024-01-14 10:27:40 +05:30
Deepesh Garg
c7509d8ebf Revert "fix: JV GLEs for auto-set against accounts" 2024-01-14 10:23:19 +05:30
rohitwaghchaure
566876ae7a fix: modified date was not set 2024-01-14 10:15:50 +05:30
rohitwaghchaure
2820a0ac0a Merge pull request #39225 from mahsem/patch-2
Update sales_taxes_and_charges.json
2024-01-14 10:15:22 +05:30
Rohit Waghchaure
116ff8241c fix: added item group in stock reco 2024-01-14 10:05:26 +05:30
rohitwaghchaure
89623aba57 Merge pull request #39201 from rmehta/remove-homepage
fix!(portal): remove Homepage
2024-01-14 09:56:25 +05:30
rohitwaghchaure
f567af49a6 fix: modified date was not updated 2024-01-14 09:48:05 +05:30
Raffael Meyer
1aecb578e6 chore: update po files (#39340) 2024-01-14 09:46:13 +05:30
Deepesh Garg
a87bb21246 Merge pull request #39084 from deepeshgarg007/pricing_rule_remove
fix: Pricing rule application/removal on qty change
2024-01-13 12:47:19 +05:30
Deepesh Garg
ec5c0deb0e Merge pull request #39166 from barredterra/remove-je-list-indicators
refactor(Journal Entry): remove unused/redundant list indicators
2024-01-13 12:21:39 +05:30
Deepesh Garg
3b14c59133 Merge pull request #39048 from barredterra/fix-pl-balance-sheet
fix: calculation of P/L in balance sheet
2024-01-13 11:09:24 +05:30
Deepesh Garg
98e2b6575d Merge pull request #39235 from GursheenK/validation-for-payment-requests
fix(minor): validate doctype before creating payment request
2024-01-13 09:45:56 +05:30
Deepesh Garg
9947bae60e Merge pull request #38984 from Gubbu77/patch-1
fix(Report): Increased the column width in the Account Balance Report
2024-01-13 09:26:42 +05:30
rohitwaghchaure
402a1b91f9 Merge pull request #39335 from s-aga-r/FIX-8359
fix: SBB Total Qty validation for SE
2024-01-12 20:59:46 +05:30
rohitwaghchaure
3b07700ef6 Merge pull request #39333 from rohitwaghchaure/fixed-added-indexing-to-improve-performance
fix: added indexing to improve performance
2024-01-12 18:39:04 +05:30
rohitwaghchaure
d3aff000d9 Merge pull request #38970 from GursheenK/item-variant-local-attributes
fix: use local attribute range in multiple item variant dialog
2024-01-12 18:37:35 +05:30
s-aga-r
d0687788b5 Merge pull request #39337 from s-aga-r/FIX-1882992786
chore: remove share, print and email permissions from Buying Settings
2024-01-12 16:47:36 +05:30
s-aga-r
3c46abca6c chore: remove share, print and email permissions from Buying Settings 2024-01-12 16:45:39 +05:30
ruthra kumar
cdd0acc672 refactor: disallow bank transactions on different currencies 2024-01-12 16:36:17 +05:30
s-aga-r
c20241fcb5 fix: SBB Total Qty validation for SE 2024-01-12 15:26:35 +05:30
Rohit Waghchaure
ac81323fec fix: added indexing to improve performance 2024-01-12 14:11:37 +05:30
ruthra kumar
6b5fa2c673 refactor: prevent foreign currency subscription for a party 2024-01-12 13:19:03 +05:30
Deepesh Garg
e4755778ae Merge pull request #39248 from GursheenK/set-against-accounts-for-backend-JVs
fix: JV GLEs for auto-set against accounts
2024-01-11 22:45:17 +05:30
Florian HENRY
6c8f52b26f fix: Payment Terms Status for Sales Order report should show all payment terms from order not only this comming from template 2024-01-11 16:00:48 +01:00
Raffael Meyer
0c47396785 Merge pull request #39293 from blaggacao/feat/add-account-preview 2024-01-11 15:12:52 +01:00
Ankush Menat
935622bde8 Update Crowdin configuration file 2024-01-11 19:08:14 +05:30
Raffael Meyer
ea33f902e7 Merge pull request #38974 from barredterra/unreconcile-bank-transaction-on-cancel 2024-01-11 14:36:24 +01:00
Ankush Menat
ea1624fba5 chore: regen po files 2024-01-11 19:03:02 +05:30
Raffael Meyer
f31c6f52e8 Merge pull request #39117 from barredterra/fix-holiday-list 2024-01-11 14:26:38 +01:00
Nabin Hait
3036a6afdc Merge pull request #39305 from GursheenK/naming_series_FY
fix: naming series variable parsing for FY
2024-01-11 18:55:14 +05:30
barredterra
f32a870a58 Merge branch 'develop' into fix-pl-balance-sheet 2024-01-11 14:03:39 +01:00
barredterra
e69f9ddf8b Merge branch 'develop' into remove-je-list-indicators 2024-01-11 14:03:13 +01:00
barredterra
2bcd032a44 Merge branch 'develop' into fix-holiday-list 2024-01-11 13:55:27 +01:00
barredterra
8039dc5194 Merge branch 'develop' into unreconcile-bank-transaction-on-cancel 2024-01-11 13:54:07 +01:00
ruthra kumar
2a195d457e Merge pull request #39320 from ruthra-kumar/possible_typeerror_in_consolidated_report
fix: possible typeerror in consolidated report
2024-01-11 16:54:30 +05:30
ruthra kumar
951e8e3a73 Merge pull request #39317 from ruthra-kumar/fix_broken_dimension_filters_in_sales_purchase_register_report
fix: broken dimension filters in Sales/Purchase register
2024-01-11 16:50:12 +05:30
ruthra kumar
268731aec4 fix: possible typeerror in consolidated report 2024-01-11 16:45:49 +05:30
ruthra kumar
7b3f9386d7 fix: broken dimension filters in Sales/Purchase register 2024-01-11 16:24:43 +05:30
Ankush Menat
d9e2427aa8 chore: migrate translations to gettext (#39313) 2024-01-11 15:46:55 +05:30
rohitwaghchaure
eb0bc5c6ad Merge pull request #39215 from rohitwaghchaure/fixed-incorrect-per-received-in-pi
fix: incorrect percentage received in purchase invoice
2024-01-11 14:50:19 +05:30
rohitwaghchaure
fde6fadf4d Merge pull request #39299 from rohitwaghchaure/fixed-cicular-dependecy-error
fix: circular dependency error on deletion of QC and Stock Entry
2024-01-11 14:49:12 +05:30
Ankush Menat
432a14c84c refactor: remove usage of raise_exception (#39309) 2024-01-11 14:02:28 +05:30
Gursheen Anand
813b7a96fb fix: reset default after test 2024-01-11 12:22:08 +05:30
Gursheen Anand
bbdf98a8f0 test: naming series variable parsing 2024-01-10 22:06:06 +05:30
Gursheen Anand
d96a777edd fix: date in master document for dictionary condition 2024-01-10 22:05:02 +05:30
rohitwaghchaure
c67b0a3a64 fix: performance issue related to stock entry (#39301) 2024-01-10 22:01:40 +05:30
Rohit Waghchaure
7cc324e31e fix: circular dependency error while deleting QC 2024-01-10 20:26:51 +05:30
Deepesh Garg
f057dc6867 Merge pull request #39256 from deepeshgarg007/opening_ignore_tempplate
fix: Ignore default payment terms template for opening invoices
2024-01-10 16:06:03 +05:30
David Arnold
e53931e27a feat(accounts): add preview for accounts 2024-01-10 11:07:39 +01:00
Raffael Meyer
6f9fe6a792 fix: wrong usage of get_single_value (#39268)
* fix: wrong usage of get_single_value

* test: fix wrong fieldname

* chore: typo

---------

Co-authored-by: Ankush Menat <ankush@frappe.io>
2024-01-10 12:32:27 +05:30
Ankush Menat
38c5ecf007 fix: set parent doctype on chart (#39286) 2024-01-10 12:26:03 +05:30
Nabin Hait
c1922ea5de Merge pull request #39052 from anandbaburajan/asset_wdv_india_dev
fix: asset WDV depreciation calc according to IT act [dev]
2024-01-10 12:17:09 +05:30
ruthra kumar
54bcbd0bc6 Merge pull request #39282 from ruthra-kumar/type_error_on_transaction_js
fix: possible typeerror on transaction.js
2024-01-10 11:53:22 +05:30
ruthra kumar
9f27ac142b fix: possible typeerror on transaction.js 2024-01-10 11:34:28 +05:30
Nabin Hait
2ef0596df2 Merge pull request #39275 from nabinhait/fetch-timesheet-in-invoice
fix: Show timesheet table after fetching data from timesheet
2024-01-10 11:33:51 +05:30
Nabin Hait
3ff562cb8a Merge pull request #39191 from nabinhait/asset-lcv-validation-fix
fix: Ignore asset qty and status validation while cancelling LCV
2024-01-10 11:33:17 +05:30
Nabin Hait
8fdf0ca2d3 Merge pull request #39207 from nabinhait/get-fixed-asset-acc
fix: Get fixed_asset_account from asset category
2024-01-10 11:32:06 +05:30
Nabin Hait
01f507ebcb Merge pull request #39238 from nabinhait/asset-purchase-amount
fix: Set asset purchase amount based on qty and valuation_rate
2024-01-10 11:31:30 +05:30
Nabin Hait
e1ba5878a3 fix: Show timesheet table after fetching data from timesheet 2024-01-10 11:26:33 +05:30
hyaray
6dceb25fb2 chore: typo 2024-01-10 10:53:14 +05:30
barredterra
5b4c5d59d8 Merge branch 'develop' into unreconcile-bank-transaction-on-cancel 2024-01-09 18:12:30 +01:00
barredterra
58343e5b7c Merge branch 'develop' into fix-holiday-list 2024-01-09 17:46:28 +01:00
Gursheen Anand
8e1f6c8149 test: split and auto set against in JV 2024-01-09 21:47:59 +05:30
Deepesh Garg
53bf44d2b8 fix: Ignore default payment terms template for opening invoices 2024-01-09 15:57:38 +05:30
Gursheen Anand
ce7d05aa1f fix: gl_map for auto-set against accounts 2024-01-09 15:08:30 +05:30
Nabin Hait
135e19d0aa fix: Set asset purchase amount based on qty and valuation_rate 2024-01-09 12:51:57 +05:30
Gursheen Anand
bb421c8b07 fix: validate doctype before creating payment request 2024-01-09 11:33:52 +05:30
David Arnold
b5be17c6df fix: use most reliable section reference per report line 2024-01-08 22:12:19 +01:00
mahsem
2b93be1139 Update sales_taxes_and_charges.json
Change Rate label to existing Tax Rate label so it can be correctly translated in other languages
2024-01-08 18:47:44 +01:00
mahsem
bd464197c4 Update purchase_taxes_and_charges.json label Rate to Tax Rate
Change Rate label to existing Tax Rate label so it can be correctly translated in other languages
2024-01-08 18:45:39 +01:00
Rohit Waghchaure
8d2c78867e fix: incorrect percentage received in purchase invoice 2024-01-08 18:17:01 +05:30
Nabin Hait
8548eae368 fix: Get fixed_asset_account from asset category 2024-01-08 16:11:04 +05:30
Rushabh Mehta
d319caa2ee fix(minor): remove Homepage patch 2024-01-08 15:51:09 +05:30
Rushabh Mehta
f01f6d50b5 fix!(portal): remove Homepage 2024-01-08 15:49:49 +05:30
Nabin Hait
e9d36242ce fix: Ignore asset qty and status validation while cancelling LCV 2024-01-08 12:45:42 +05:30
David Arnold
b73507abe0 Merge remote-tracking branch 'origin/develop' into feat/so-po-advance-payment-status 2024-01-05 21:36:14 +01:00
barredterra
5d33bbaff0 refactor(Journal Entry): remove unused/redundant list indicators 2024-01-05 17:26:54 +01:00
barredterra
60329ade9e test: improve test for local holidays 2024-01-04 11:04:25 +01:00
barredterra
300aaa39fe fix: consider all years in holiday list 2024-01-03 13:39:28 +01:00
barredterra
73ecf51a27 test: balance sheet 2024-01-02 20:39:32 +01:00
barredterra
0d3a77dce9 fix: calculation of P/L in balance sheet 2024-01-02 17:26:29 +01:00
Deepesh Garg
f52d7c7665 fix: Pricing rule application/removal on qty change 2024-01-02 13:37:39 +05:30
anandbaburajan
026824880d fix: asset WDV depreciation calc according to IT act 2024-01-01 00:23:19 +05:30
Indrajith.vs
37767738b0 fix(Report): Increased the column width in the Account Balance Report 2023-12-28 12:12:52 +05:30
barredterra
517bedeb7e test: cancel voucher linked to Bank Transaction 2023-12-28 00:00:04 +01:00
barredterra
0a95b38166 fix: unreconcile Bank Transaction on cancel of payment voucher 2023-12-27 23:05:37 +01:00
Gursheen Anand
43fed29514 fix: use child table values instead of global min max 2023-12-27 19:32:48 +05:30
David Arnold
f73685f4f6 Merge remote-tracking branch 'origin/develop' into feat/so-po-advance-payment-status 2023-12-20 12:47:48 +01:00
Dany Robert
a8949174c8 chore: avoid explicit escaping for precision
Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2023-12-09 09:30:17 +05:30
David Arnold
e824cd012b Merge remote-tracking branch 'upstream/develop' into feat/so-po-advance-payment-status 2023-12-04 13:35:32 +01:00
Dany Robert
383a4b132e chore: change f-string to sql params 2023-11-21 12:46:56 +00:00
Dany Robert
bfaa93b0ca fix: honour currency precision while fetching balance 2023-11-20 09:43:02 +00:00
David Arnold
c2f0fadb6e Merge remote-tracking branch 'upstream/develop' into feat/so-po-advance-payment-status 2023-11-13 10:06:14 +01:00
David Arnold
c78fdaae90 Merge remote-tracking branch 'upstream/develop' into feat/so-po-advance-payment-status 2023-10-30 17:25:08 +01:00
David Arnold
8b21ca2db9 fixup! feat(payment): add advance payment status to advance payment doctypes to better track advance payments 2023-10-17 00:12:19 +02:00
David Arnold
e97af14ff4 fixup! feat(payment): add advance payment status to advance payment doctypes to better track advance payments 2023-10-10 23:50:57 +02:00
David Arnold
c809e61103 feat(payment): add advance payment status to advance payment doctypes to better track advance payments 2023-10-10 22:33:06 +02:00
326 changed files with 1467228 additions and 568667 deletions

View File

@@ -20,6 +20,18 @@ jobs:
- name: Install and Run Pre-commit
uses: pre-commit/action@v3.0.0
semgrep:
name: semgrep
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: pip
- name: Download Semgrep rules
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules

22
.github/workflows/patch_faux.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
name: Skipped Patch Test
on:
pull_request:
paths:
- "**.js"
- "**.css"
- "**.md"
- "**.html"
- "**.csv"
jobs:
test:
runs-on: ubuntu-latest
name: Patch Test
steps:
- name: Pass skipped tests unconditionally
run: "echo Skipped"

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 18
node-version: 20
- name: Setup dependencies
run: |
npm install @semantic-release/git @semantic-release/exec --no-save

View File

@@ -0,0 +1,24 @@
# Tests are skipped for these files but github doesn't allow "passing" hence this is required.
name: Skipped Tests
on:
pull_request:
paths:
- "**.js"
- "**.css"
- "**.md"
- "**.html"
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
container: [1, 2, 3, 4]
name: Python Unit Tests
steps:
- name: Pass skipped tests unconditionally
run: "echo Skipped"

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /erpnext/locale/main.pot
translation: /erpnext/locale/%two_letters_code%.po

View File

@@ -358,11 +358,9 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
account_currency = get_account_currency(item.expense_account or item.income_account)
if doc.doctype == "Sales Invoice":
against_type = "Customer"
against, project = doc.customer, doc.project
credit_account, debit_account = item.income_account, item.deferred_revenue_account
else:
against_type = "Supplier"
against, project = doc.supplier, item.project
credit_account, debit_account = item.deferred_expense_account, item.expense_account
@@ -415,7 +413,6 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
doc,
credit_account,
debit_account,
against_type,
against,
amount,
base_amount,
@@ -497,7 +494,6 @@ def make_gl_entries(
doc,
credit_account,
debit_account,
against_type,
against,
amount,
base_amount,
@@ -519,9 +515,7 @@ def make_gl_entries(
doc.get_gl_dict(
{
"account": credit_account,
"against_type": against_type,
"against": against,
"against_link": against,
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": cost_center,
@@ -540,9 +534,7 @@ def make_gl_entries(
doc.get_gl_dict(
{
"account": debit_account,
"against_type": against_type,
"against": against,
"against_link": against,
"debit": base_amount,
"debit_in_account_currency": amount,
"cost_center": cost_center,

View File

@@ -108,6 +108,7 @@
"fieldname": "parent_account",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"in_preview": 1,
"label": "Parent Account",
"oldfieldname": "parent_account",
"oldfieldtype": "Link",
@@ -192,7 +193,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2023-07-20 18:18:44.405723",
"modified": "2024-01-10 04:57:33.681676",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@@ -249,8 +250,9 @@
],
"search_fields": "account_number",
"show_name_in_global_search": 1,
"show_preview_popup": 1,
"sort_field": "modified",
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}

View File

@@ -36,16 +36,16 @@
}
},
"Fixed Assets": {
"Capital Equipments": {
"Capital Equipment": {
"account_type": "Fixed Asset"
},
"Electronic Equipments": {
"Electronic Equipment": {
"account_type": "Fixed Asset"
},
"Furnitures and Fixtures": {
"Furniture and Fixtures": {
"account_type": "Fixed Asset"
},
"Office Equipments": {
"Office Equipment": {
"account_type": "Fixed Asset"
},
"Plants and Machineries": {

View File

@@ -23,13 +23,13 @@ def get():
_("Tax Assets"): {"is_group": 1},
},
_("Fixed Assets"): {
_("Capital Equipments"): {"account_type": "Fixed Asset"},
_("Electronic Equipments"): {"account_type": "Fixed Asset"},
_("Furnitures and Fixtures"): {"account_type": "Fixed Asset"},
_("Office Equipments"): {"account_type": "Fixed Asset"},
_("Capital Equipment"): {"account_type": "Fixed Asset"},
_("Electronic Equipment"): {"account_type": "Fixed Asset"},
_("Furniture and Fixtures"): {"account_type": "Fixed Asset"},
_("Office Equipment"): {"account_type": "Fixed Asset"},
_("Plants and Machineries"): {"account_type": "Fixed Asset"},
_("Buildings"): {"account_type": "Fixed Asset"},
_("Softwares"): {"account_type": "Fixed Asset"},
_("Software"): {"account_type": "Fixed Asset"},
_("Accumulated Depreciation"): {"account_type": "Accumulated Depreciation"},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",

View File

@@ -36,13 +36,13 @@ def get():
"account_number": "1100-1600",
},
_("Fixed Assets"): {
_("Capital Equipments"): {"account_type": "Fixed Asset", "account_number": "1710"},
_("Electronic Equipments"): {"account_type": "Fixed Asset", "account_number": "1720"},
_("Furnitures and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
_("Office Equipments"): {"account_type": "Fixed Asset", "account_number": "1740"},
_("Capital Equipment"): {"account_type": "Fixed Asset", "account_number": "1710"},
_("Electronic Equipment"): {"account_type": "Fixed Asset", "account_number": "1720"},
_("Furniture and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
_("Office Equipment"): {"account_type": "Fixed Asset", "account_number": "1740"},
_("Plants and Machineries"): {"account_type": "Fixed Asset", "account_number": "1750"},
_("Buildings"): {"account_type": "Fixed Asset", "account_number": "1760"},
_("Softwares"): {"account_type": "Fixed Asset", "account_number": "1770"},
_("Software"): {"account_type": "Fixed Asset", "account_number": "1770"},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation",
"account_number": "1780",

View File

@@ -119,7 +119,7 @@ class TestAccount(unittest.TestCase):
InvalidAccountMergeError,
merge_account,
"Capital Stock - _TC",
"Softwares - _TC",
"Software - _TC",
)
# Raise error as currency doesn't match

View File

@@ -55,7 +55,7 @@ class BankAccount(Document):
def validate_company(self):
if self.is_company_account and not self.company:
frappe.throw(_("Company is manadatory for company account"))
frappe.throw(_("Company is mandatory for company account"))
def validate_iban(self):
"""

View File

@@ -48,11 +48,11 @@ class BankGuarantee(Document):
def on_submit(self):
if not self.bank_guarantee_number:
frappe.throw(_("Enter the Bank Guarantee Number before submittting."))
frappe.throw(_("Enter the Bank Guarantee Number before submitting."))
if not self.name_of_beneficiary:
frappe.throw(_("Enter the name of the Beneficiary before submittting."))
frappe.throw(_("Enter the name of the Beneficiary before submitting."))
if not self.bank:
frappe.throw(_("Enter the name of the bank or lending institution before submittting."))
frappe.throw(_("Enter the name of the bank or lending institution before submitting."))
@frappe.whitelist()

View File

@@ -76,6 +76,7 @@ class TestBankReconciliationTool(AccountsTestMixin, FrappeTestCase):
"deposit": 100,
"bank_account": self.bank_account,
"reference_number": "123",
"currency": "INR",
}
)
.save()

View File

@@ -3,6 +3,7 @@
import frappe
from frappe import _
from frappe.model.docstatus import DocStatus
from frappe.model.document import Document
from frappe.utils import flt
@@ -48,6 +49,24 @@ class BankTransaction(Document):
def validate(self):
self.validate_duplicate_references()
self.validate_currency()
def validate_currency(self):
"""
Bank Transaction should be on the same currency as the Bank Account.
"""
if self.currency and self.bank_account:
account = frappe.get_cached_value("Bank Account", self.bank_account, "account")
account_currency = frappe.get_cached_value("Account", account, "account_currency")
if self.currency != account_currency:
frappe.throw(
_(
"Transaction currency: {0} cannot be different from Bank Account({1}) currency: {2}"
).format(
frappe.bold(self.currency), frappe.bold(self.bank_account), frappe.bold(account_currency)
)
)
def set_status(self):
if self.docstatus == 2:
@@ -415,3 +434,21 @@ def unclear_reference_payment(doctype, docname, bt_name):
bt = frappe.get_doc("Bank Transaction", bt_name)
set_voucher_clearance(doctype, docname, None, bt)
return docname
def remove_from_bank_transaction(doctype, docname):
"""Remove a (cancelled) voucher from all Bank Transactions."""
for bt_name in get_reconciled_bank_transactions(doctype, docname):
bt = frappe.get_doc("Bank Transaction", bt_name)
if bt.docstatus == DocStatus.cancelled():
continue
modified = False
for pe in bt.payment_entries:
if pe.payment_document == doctype and pe.payment_entry == docname:
bt.remove(pe)
modified = True
if modified:
bt.save()

View File

@@ -2,10 +2,10 @@
# See license.txt
import json
import unittest
import frappe
from frappe import utils
from frappe.model.docstatus import DocStatus
from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
@@ -81,6 +81,29 @@ class TestBankTransaction(FrappeTestCase):
clearance_date = frappe.db.get_value("Payment Entry", payment.name, "clearance_date")
self.assertFalse(clearance_date)
def test_cancel_voucher(self):
bank_transaction = frappe.get_doc(
"Bank Transaction",
dict(description="1512567 BG/000003025 OPSKATTUZWXXX AT776000000098709849 Herr G"),
)
payment = frappe.get_doc("Payment Entry", dict(party="Mr G", paid_amount=1700))
vouchers = json.dumps(
[
{
"payment_doctype": "Payment Entry",
"payment_name": payment.name,
"amount": bank_transaction.unallocated_amount,
}
]
)
reconcile_vouchers(bank_transaction.name, vouchers)
payment.reload()
payment.cancel()
bank_transaction.reload()
self.assertEqual(bank_transaction.docstatus, DocStatus.submitted())
self.assertEqual(bank_transaction.unallocated_amount, 1700)
self.assertEqual(bank_transaction.payment_entries, [])
# Check if ERPNext can correctly filter a linked payments based on the debit/credit amount
def test_debit_credit_output(self):
bank_transaction = frappe.get_doc(

View File

@@ -80,7 +80,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto"
"label": "Valid Up To"
},
{
"depends_on": "eval: doc.coupon_type == \"Promotional\"",
@@ -115,7 +115,7 @@
"read_only": 1
}
],
"modified": "2019-10-19 14:48:14.602481",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",

View File

@@ -82,11 +82,11 @@
"icon": "fa fa-calendar",
"idx": 1,
"links": [],
"modified": "2020-11-05 12:16:53.081573",
"modified": "2024-01-17 13:06:01.608953",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
"owner": "Administrator",
"owner": "Administrator",
"permissions": [
{
"create": 1,
@@ -118,6 +118,14 @@
{
"read": 1,
"role": "Employee"
},
{
"read": 1,
"role": "Accounts Manager"
},
{
"read": 1,
"role": "Stock Manager"
}
],
"show_name_in_global_search": 1,

View File

@@ -39,7 +39,7 @@ def test_record_generator():
]
start = 2012
end = now_datetime().year + 5
end = now_datetime().year + 25
for year in range(start, end):
test_records.append(
{

View File

@@ -17,9 +17,7 @@
"account_currency",
"debit_in_account_currency",
"credit_in_account_currency",
"against_type",
"against",
"against_link",
"against_voucher_type",
"against_voucher",
"voucher_type",
@@ -131,13 +129,6 @@
"label": "Credit Amount in Account Currency",
"options": "account_currency"
},
{
"fieldname": "against_type",
"fieldtype": "Link",
"in_filter": 1,
"label": "Against Type",
"options": "DocType"
},
{
"fieldname": "against",
"fieldtype": "Text",
@@ -146,13 +137,6 @@
"oldfieldname": "against",
"oldfieldtype": "Text"
},
{
"fieldname": "against_link",
"fieldtype": "Dynamic Link",
"in_filter": 1,
"label": "Against",
"options": "against_type"
},
{
"fieldname": "against_voucher_type",
"fieldtype": "Link",
@@ -306,7 +290,7 @@
"idx": 1,
"in_create": 1,
"links": [],
"modified": "2023-12-18 15:38:14.006208",
"modified": "2023-09-26 12:03:23.031733",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",

View File

@@ -154,7 +154,7 @@ frappe.ui.form.on('Invoice Discounting', {
}
});
},
primary_action_label: __('Get Invocies')
primary_action_label: __('Get Invoices')
});
d.show();
},

View File

@@ -153,9 +153,7 @@ class InvoiceDiscounting(AccountsController):
"account": inv.debit_to,
"party_type": "Customer",
"party": d.customer,
"against_type": "Account",
"against": self.accounts_receivable_credit,
"against_link": self.accounts_receivable_credit,
"credit": outstanding_in_company_currency,
"credit_in_account_currency": outstanding_in_company_currency
if inv.party_account_currency == company_currency
@@ -175,9 +173,7 @@ class InvoiceDiscounting(AccountsController):
"account": self.accounts_receivable_credit,
"party_type": "Customer",
"party": d.customer,
"against_type": "Account",
"against": inv.debit_to,
"against_link": inv.debit_to,
"debit": outstanding_in_company_currency,
"debit_in_account_currency": outstanding_in_company_currency
if ar_credit_account_currency == company_currency

View File

@@ -8,7 +8,7 @@ frappe.provide("erpnext.journal_entry");
frappe.ui.form.on("Journal Entry", {
setup: function(frm) {
frm.add_fetch("bank_account", "account", "account");
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries"];
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger", 'Asset', 'Asset Movement', 'Asset Depreciation Schedule', "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries", "Bank Transaction"];
},
refresh: function(frm) {
@@ -220,16 +220,6 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro
return erpnext.journal_entry.account_query(me.frm);
});
me.frm.set_query("against_account_link", "accounts", function(doc, cdt, cdn) {
return erpnext.journal_entry.against_account_query(me.frm);
});
me.frm.set_query("against_type", "accounts", function(){
return {
query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_type",
}
})
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
@@ -601,21 +591,6 @@ $.extend(erpnext.journal_entry, {
return { filters: filters };
},
against_account_query: function(frm) {
if (frm.doc.against_type != "Account"){
return { filters: {} };
}
else {
let filters = { company: frm.doc.company, is_group: 0 };
if(!frm.doc.multi_currency) {
$.extend(filters, {
account_currency: ['in', [frappe.get_doc(":Company", frm.doc.company).default_currency, null]]
});
}
return { filters: filters };
}
},
reverse_journal_entry: function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.make_reverse_journal_entry",

View File

@@ -186,9 +186,12 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
for d in self.get("accounts"):
if d.is_advance:
if d.reference_type in frappe.get_hooks("advance_payment_doctypes"):
if d.reference_type in advance_payment_doctypes:
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
for voucher_type, order_list in advance_paid.items():
@@ -304,7 +307,6 @@ class JournalEntry(AccountsController):
"account": tax_withholding_details.get("account_head"),
rev_debit_or_credit: tax_withholding_details.get("tax_amount"),
"against_account": parties[0],
"against_account_link": parties[0],
},
)
@@ -751,90 +753,27 @@ class JournalEntry(AccountsController):
)
def set_against_account(self):
accounts_debited, accounts_credited = [], []
if self.voucher_type in ("Deferred Revenue", "Deferred Expense"):
for d in self.get("accounts"):
if d.reference_type == "Sales Invoice":
against_type = "Customer"
field = "customer"
else:
against_type = "Supplier"
field = "supplier"
against_account = frappe.db.get_value(d.reference_type, d.reference_name, against_type.lower())
d.against_type = against_type
d.against_account_link = against_account
d.against_account = frappe.db.get_value(d.reference_type, d.reference_name, field)
else:
self.get_debited_credited_accounts()
if len(self.accounts_credited) > 1 and len(self.accounts_debited) > 1:
self.auto_set_against_accounts()
return
self.get_against_accounts()
for d in self.get("accounts"):
if flt(d.debit) > 0:
accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0:
accounts_credited.append(d.party or d.account)
def auto_set_against_accounts(self):
for i in range(0, len(self.accounts), 2):
acc = self.accounts[i]
against_acc = self.accounts[i + 1]
if acc.debit_in_account_currency > 0:
current_val = acc.debit_in_account_currency * flt(acc.exchange_rate)
against_val = against_acc.credit_in_account_currency * flt(against_acc.exchange_rate)
else:
current_val = acc.credit_in_account_currency * flt(acc.exchange_rate)
against_val = against_acc.debit_in_account_currency * flt(against_acc.exchange_rate)
if current_val == against_val:
acc.against_type = against_acc.party_type or "Account"
against_acc.against_type = acc.party_type or "Account"
acc.against_account_link = against_acc.party or against_acc.account
against_acc.against_account_link = acc.party or acc.account
else:
frappe.msgprint(
_(
"Unable to automatically determine {0} accounts. Set them up in the {1} table if needed."
).format(frappe.bold("against"), frappe.bold("Accounting Entries")),
alert=True,
)
break
def get_against_accounts(self):
self.against_accounts = []
self.split_account = {}
self.get_debited_credited_accounts()
if self.separate_against_account_entries:
no_of_credited_acc, no_of_debited_acc = len(self.accounts_credited), len(self.accounts_debited)
if no_of_credited_acc <= 1 and no_of_debited_acc <= 1:
self.set_against_accounts_for_single_dr_cr()
self.separate_against_account_entries = 0
elif no_of_credited_acc == 1:
self.against_accounts = self.accounts_debited
self.split_account = self.accounts_credited[0]
elif no_of_debited_acc == 1:
self.against_accounts = self.accounts_credited
self.split_account = self.accounts_debited[0]
def get_debited_credited_accounts(self):
self.accounts_debited, self.accounts_credited = [], []
self.separate_against_account_entries = 1
for d in self.get("accounts"):
if flt(d.debit) > 0:
self.accounts_debited.append(d)
elif flt(d.credit) > 0:
self.accounts_credited.append(d)
if d.against_account_link:
self.separate_against_account_entries = 0
break
def set_against_accounts_for_single_dr_cr(self):
against_account = None
for d in self.accounts:
if flt(d.debit) > 0:
against_account = self.accounts_credited[0]
elif flt(d.credit) > 0:
against_account = self.accounts_debited[0]
if against_account:
d.against_type = against_account.party_type or "Account"
d.against_account = against_account.party or against_account.account
d.against_account_link = against_account.party or against_account.account
for d in self.get("accounts"):
if flt(d.debit) > 0:
d.against_account = ", ".join(list(set(accounts_credited)))
if flt(d.credit) > 0:
d.against_account = ", ".join(list(set(accounts_debited)))
def validate_debit_credit_amount(self):
if not (self.voucher_type == "Exchange Gain Or Loss" and self.multi_currency):
@@ -1031,108 +970,42 @@ class JournalEntry(AccountsController):
def build_gl_map(self):
gl_map = []
conversion_rate_map = self.get_conversion_rate_map()
transaction_currency_map = self.get_transaction_currency_map()
company_currency = erpnext.get_company_currency(self.company)
self.get_against_accounts()
for d in self.get("accounts"):
if d.debit or d.credit or (self.voucher_type == "Exchange Gain Or Loss"):
r = [d.user_remark, self.remark]
r = [x for x in r if x]
remarks = "\n".join(r)
gl_dict = self.get_gl_dict(
{
"account": d.account,
"party_type": d.party_type,
"due_date": self.due_date,
"party": d.party,
"debit": flt(d.debit, d.precision("debit")),
"credit": flt(d.credit, d.precision("credit")),
"account_currency": d.account_currency,
"debit_in_account_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
),
"credit_in_account_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
),
"against_voucher_type": d.reference_type,
"against_voucher": d.reference_name,
"remarks": remarks,
"voucher_detail_no": d.reference_detail_no,
"cost_center": d.cost_center,
"project": d.project,
"finance_book": self.finance_book,
"conversion_rate": conversion_rate_map.get(d.against_account_link, 1)
if d.account_currency == company_currency
else 1,
"currency": transaction_currency_map.get(d.against_account_link, d.account_currency)
if d.account_currency == company_currency
else d.account_currency,
},
item=d,
gl_map.append(
self.get_gl_dict(
{
"account": d.account,
"party_type": d.party_type,
"due_date": self.due_date,
"party": d.party,
"against": d.against_account,
"debit": flt(d.debit, d.precision("debit")),
"credit": flt(d.credit, d.precision("credit")),
"account_currency": d.account_currency,
"debit_in_account_currency": flt(
d.debit_in_account_currency, d.precision("debit_in_account_currency")
),
"credit_in_account_currency": flt(
d.credit_in_account_currency, d.precision("credit_in_account_currency")
),
"against_voucher_type": d.reference_type,
"against_voucher": d.reference_name,
"remarks": remarks,
"voucher_detail_no": d.reference_detail_no,
"cost_center": d.cost_center,
"project": d.project,
"finance_book": self.finance_book,
},
item=d,
)
)
if not self.separate_against_account_entries:
gl_dict.update(
{
"against_type": d.against_type,
"against_link": d.against_account_link,
}
)
gl_map.append(gl_dict)
elif d in self.against_accounts:
gl_dict.update(
{
"against_type": self.split_account.get("party_type") or "Account",
"against": self.split_account.get("party") or self.split_account.get("account"),
"against_link": self.split_account.get("party") or self.split_account.get("account"),
}
)
gl_map.append(gl_dict)
else:
for against_account in self.against_accounts:
against_account = against_account.as_dict()
debit = against_account.credit or against_account.credit_in_account_currency
credit = against_account.debit or against_account.debit_in_account_currency
gl_dict = gl_dict.copy()
gl_dict.update(
{
"against_type": against_account.party_type or "Account",
"against": against_account.party or against_account.account,
"against_link": against_account.party or against_account.account,
"debit": flt(debit, d.precision("debit")),
"credit": flt(credit, d.precision("credit")),
"account_currency": d.account_currency,
"debit_in_account_currency": flt(
debit / d.exchange_rate, d.precision("debit_in_account_currency")
),
"credit_in_account_currency": flt(
credit / d.exchange_rate, d.precision("credit_in_account_currency")
),
}
)
gl_map.append(gl_dict)
return gl_map
def get_transaction_currency_map(self):
transaction_currency_map = {}
for account in self.get("accounts"):
transaction_currency_map.setdefault(account.party or account.account, account.account_currency)
return transaction_currency_map
def get_conversion_rate_map(self):
conversion_rate_map = {}
for account in self.get("accounts"):
conversion_rate_map.setdefault(account.party or account.account, account.exchange_rate)
return conversion_rate_map
def make_gl_entries(self, cancel=0, adv_adj=0):
from erpnext.accounts.general_ledger import make_gl_entries
@@ -1755,10 +1628,3 @@ def make_reverse_journal_entry(source_name, target_doc=None):
)
return doclist
@frappe.whitelist()
def get_against_type(doctype, txt, searchfield, start, page_len, filters):
against_types = frappe.db.get_list("Party Type", pluck="name") + ["Account"]
doctype = frappe.qb.DocType("DocType")
return frappe.qb.from_(doctype).select(doctype.name).where(doctype.name.isin(against_types)).run()

View File

@@ -1,12 +1,18 @@
frappe.listview_settings['Journal Entry'] = {
add_fields: ["voucher_type", "posting_date", "total_debit", "company", "user_remark"],
get_indicator: function(doc) {
if(doc.docstatus==0) {
return [__("Draft", "red", "docstatus,=,0")]
} else if(doc.docstatus==2) {
return [__("Cancelled", "grey", "docstatus,=,2")]
} else {
return [__(doc.voucher_type), "blue", "voucher_type,=," + doc.voucher_type]
frappe.listview_settings["Journal Entry"] = {
add_fields: [
"voucher_type",
"posting_date",
"total_debit",
"company",
"user_remark",
],
get_indicator: function (doc) {
if (doc.docstatus === 1) {
return [
__(doc.voucher_type),
"blue",
`voucher_type,=,${doc.voucher_type}`,
];
}
}
},
};

View File

@@ -37,9 +37,7 @@
"col_break3",
"is_advance",
"user_remark",
"against_type",
"against_account",
"against_account_link"
"against_account"
],
"fields": [
{
@@ -252,21 +250,14 @@
"print_hide": 1
},
{
"fieldname": "against_account",
"fieldtype": "Text",
"hidden": 1,
"label": "Against Account",
"no_copy": 1,
"oldfieldname": "against_account",
"oldfieldtype": "Text",
"print_hide": 1
},
{
"fieldname": "against_account_link",
"fieldtype": "Dynamic Link",
"fieldname": "against_account",
"fieldtype": "Text",
"hidden": 1,
"label": "Against Account",
"no_copy": 1,
"options": "against_type"
"oldfieldname": "against_account",
"oldfieldtype": "Text",
"print_hide": 1
},
{
"collapsible": 1,
@@ -290,18 +281,12 @@
"hidden": 1,
"label": "Reference Detail No",
"no_copy": 1
},
{
"fieldname": "against_type",
"fieldtype": "Link",
"label": "Against Type",
"options": "DocType"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-12-02 23:21:22.205409",
"modified": "2023-12-03 23:21:22.205409",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@@ -270,7 +270,7 @@ def start_import(invoices):
errors, "<a href='/app/List/Error Log' class='variant-click'>Error Log</a>"
),
indicator="red",
title=_("Error Occured"),
title=_("Error Occurred"),
)
return names

View File

@@ -9,7 +9,7 @@ erpnext.accounts.taxes.setup_tax_filters("Advance Taxes and Charges");
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payment', 'Unreconcile Payment Entries'];
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', 'Repost Payment Ledger','Repost Accounting Ledger', 'Unreconcile Payment', 'Unreconcile Payment Entries', "Bank Transaction"];
if(frm.doc.__islocal) {
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
@@ -640,7 +640,7 @@ frappe.ui.form.on('Payment Entry', {
get_outstanding_invoices_or_orders: function(frm, get_outstanding_invoices, get_orders_to_be_billed) {
const today = frappe.datetime.get_today();
const fields = [
let fields = [
{fieldtype:"Section Break", label: __("Posting Date")},
{fieldtype:"Date", label: __("From Date"),
fieldname:"from_posting_date", default:frappe.datetime.add_days(today, -30)},
@@ -655,18 +655,29 @@ frappe.ui.form.on('Payment Entry', {
fieldname:"outstanding_amt_greater_than", default: 0},
{fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
{fieldtype:"Section Break"},
{fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
"get_query": function() {
return {
"filters": {"company": frm.doc.company}
}
];
if (frm.dimension_filters) {
let column_break_insertion_point = Math.ceil((frm.dimension_filters.length)/2);
fields.push({fieldtype:"Section Break"});
frm.dimension_filters.map((elem, idx)=>{
fields.push({
fieldtype: "Link",
label: elem.document_type == "Cost Center" ? "Cost Center" : elem.label,
options: elem.document_type,
fieldname: elem.fieldname || elem.document_type
});
if(idx+1 == column_break_insertion_point) {
fields.push({fieldtype:"Column Break"});
}
},
{fieldtype:"Column Break"},
});
}
fields = fields.concat([
{fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
];
]);
let btn_text = "";
@@ -933,7 +944,7 @@ frappe.ui.form.on('Payment Entry', {
if(frm.doc.payment_type == "Receive"
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
unallocated_amount = (frm.doc.base_received_amount + total_deductions + flt(frm.doc.base_total_taxes_and_charges)
unallocated_amount = (frm.doc.base_received_amount + total_deductions - flt(frm.doc.base_total_taxes_and_charges)
- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
} else if (frm.doc.payment_type == "Pay"
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions

View File

@@ -13,6 +13,7 @@ from pypika import Case
from pypika.functions import Coalesce, Sum
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
from erpnext.accounts.doctype.bank_account.bank_account import (
get_bank_account_details,
get_party_bank_account,
@@ -189,7 +190,7 @@ class PaymentEntry(AccountsController):
def set_liability_account(self):
# Auto setting liability account should only be done during 'draft' status
if self.docstatus > 0:
if self.docstatus > 0 or self.payment_type == "Internal Transfer":
return
if not frappe.db.get_value(
@@ -925,7 +926,10 @@ class PaymentEntry(AccountsController):
def calculate_base_allocated_amount_for_reference(self, d) -> float:
base_allocated_amount = 0
if d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
if d.reference_doctype in advance_payment_doctypes:
# When referencing Sales/Purchase Order, use the source/target exchange rate depending on payment type.
# This is so there are no Exchange Gain/Loss generated for such doctypes
@@ -1144,9 +1148,7 @@ class PaymentEntry(AccountsController):
"account": self.party_account,
"party_type": self.party_type,
"party": self.party,
"against_type": "Account",
"against": against_account,
"against_link": against_account,
"account_currency": self.party_account_currency,
"cost_center": self.cost_center,
},
@@ -1311,9 +1313,7 @@ class PaymentEntry(AccountsController):
{
"account": self.paid_from,
"account_currency": self.paid_from_account_currency,
"against_type": self.party_type if self.payment_type == "Pay" else "Account",
"against": self.party if self.payment_type == "Pay" else self.paid_to,
"against_link": self.party if self.payment_type == "Pay" else self.paid_to,
"credit_in_account_currency": self.paid_amount,
"credit": self.base_paid_amount,
"cost_center": self.cost_center,
@@ -1328,9 +1328,7 @@ class PaymentEntry(AccountsController):
{
"account": self.paid_to,
"account_currency": self.paid_to_account_currency,
"against_type": self.party_type if self.payment_type == "Receive" else "Account",
"against": self.party if self.payment_type == "Receive" else self.paid_from,
"against_link": self.party if self.payment_type == "Receive" else self.paid_from,
"debit_in_account_currency": self.received_amount,
"debit": self.base_received_amount,
"cost_center": self.cost_center,
@@ -1354,7 +1352,6 @@ class PaymentEntry(AccountsController):
rev_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit"
against = self.party or self.paid_to
against_type = self.party_type or "Account"
payment_account = self.get_party_account_for_taxes()
tax_amount = d.tax_amount
base_tax_amount = d.base_tax_amount
@@ -1363,9 +1360,7 @@ class PaymentEntry(AccountsController):
self.get_gl_dict(
{
"account": d.account_head,
"against_type": against_type,
"against": against,
"against_link": against,
dr_or_cr: tax_amount,
dr_or_cr + "_in_account_currency": base_tax_amount
if account_currency == self.company_currency
@@ -1390,9 +1385,7 @@ class PaymentEntry(AccountsController):
self.get_gl_dict(
{
"account": payment_account,
"against_type": against_type,
"against": against,
"against_link": against,
rev_dr_or_cr: tax_amount,
rev_dr_or_cr + "_in_account_currency": base_tax_amount
if account_currency == self.company_currency
@@ -1417,9 +1410,7 @@ class PaymentEntry(AccountsController):
{
"account": d.account,
"account_currency": account_currency,
"against_type": self.party_type or "Account",
"against": self.party or self.paid_from,
"against_link": self.party or self.paid_from,
"debit_in_account_currency": d.amount,
"debit": d.amount,
"cost_center": d.cost_center,
@@ -1436,8 +1427,11 @@ class PaymentEntry(AccountsController):
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
if d.allocated_amount and d.reference_doctype in advance_payment_doctypes:
frappe.get_doc(
d.reference_doctype, d.reference_name, for_update=True
).set_total_advance_paid()
@@ -1684,6 +1678,13 @@ def get_outstanding_reference_documents(args, validate=False):
condition += " and cost_center='%s'" % args.get("cost_center")
accounting_dimensions_filter.append(ple.cost_center == args.get("cost_center"))
# dynamic dimension filters
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if args.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, args.get(dim.fieldname))
accounting_dimensions_filter.append(ple[dim.fieldname] == args.get(dim.fieldname))
date_fields_dict = {
"posting_date": ["from_posting_date", "to_posting_date"],
"due_date": ["from_due_date", "to_due_date"],
@@ -1917,6 +1918,12 @@ def get_orders_to_be_billed(
if doc and hasattr(doc, "cost_center") and doc.cost_center:
condition = " and cost_center='%s'" % cost_center
# dynamic dimension filters
active_dimensions = get_dimensions()[0]
for dim in active_dimensions:
if filters.get(dim.fieldname):
condition += " and {0}='{1}'".format(dim.fieldname, filters.get(dim.fieldname))
if party_account_currency == company_currency:
grand_total_field = "base_grand_total"
rounded_total_field = "base_rounded_total"

View File

@@ -95,6 +95,8 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
this.frm.change_custom_button_type(__('Allocate'), null, 'default');
}
this.frm.trigger("set_query_for_dimension_filters");
// check for any running reconciliation jobs
if (this.frm.doc.receivable_payable_account) {
this.frm.call({
@@ -125,6 +127,25 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
}
}
set_query_for_dimension_filters() {
frappe.call({
method: "erpnext.accounts.doctype.payment_reconciliation.payment_reconciliation.get_queries_for_dimension_filters",
args: {
company: this.frm.doc.company,
},
callback: (r) => {
if (!r.exc && r.message) {
r.message.forEach(x => {
this.frm.set_query(x.fieldname, () => {
return {
'filters': x.filters
};
});
});
}
}
});
}
company() {
this.frm.set_value('party', '');

View File

@@ -25,7 +25,9 @@
"invoice_limit",
"payment_limit",
"bank_cash_account",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"sec_break1",
"invoice_name",
"invoices",
@@ -208,6 +210,18 @@
"fieldname": "payment_name",
"fieldtype": "Data",
"label": "Filter on Payment"
},
{
"collapsible": 1,
"collapsible_depends_on": "eval: doc.invoices.length == 0",
"depends_on": "eval:doc.receivable_payable_account",
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions Filter"
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
@@ -215,7 +229,7 @@
"is_virtual": 1,
"issingle": 1,
"links": [],
"modified": "2023-11-17 17:33:55.701726",
"modified": "2023-12-14 13:38:16.264013",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",

View File

@@ -10,6 +10,7 @@ from frappe.query_builder.custom import ConstantColumn
from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import (
is_any_doc_running,
)
@@ -70,6 +71,7 @@ class PaymentReconciliation(Document):
self.common_filter_conditions = []
self.accounting_dimension_filter_conditions = []
self.ple_posting_date_filter = []
self.dimensions = get_dimensions()[0]
def load_from_db(self):
# 'modified' attribute is required for `run_doc_method` to work properly.
@@ -172,6 +174,14 @@ class PaymentReconciliation(Document):
if self.payment_name:
condition.update({"name": self.payment_name})
# pass dynamic dimension filter values to query builder
dimensions = {}
for x in self.dimensions:
dimension = x.fieldname
if self.get(dimension):
dimensions.update({dimension: self.get(dimension)})
condition.update({"accounting_dimensions": dimensions})
payment_entries = get_advance_payment_entries_for_regional(
self.party_type,
self.party,
@@ -185,66 +195,67 @@ class PaymentReconciliation(Document):
return payment_entries
def get_jv_entries(self):
condition = self.get_conditions()
je = qb.DocType("Journal Entry")
jea = qb.DocType("Journal Entry Account")
conditions = self.get_journal_filter_conditions()
# Dimension filters
for x in self.dimensions:
dimension = x.fieldname
if self.get(dimension):
conditions.append(jea[dimension] == self.get(dimension))
if self.payment_name:
condition += f" and t1.name like '%%{self.payment_name}%%'"
conditions.append(je.name.like(f"%%{self.payment_name}%%"))
if self.get("cost_center"):
condition += f" and t2.cost_center = '{self.cost_center}' "
conditions.append(jea.cost_center == self.cost_center)
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
else "debit_in_account_currency"
)
conditions.append(jea[dr_or_cr].gt(0))
bank_account_condition = (
"t2.against_account like %(bank_cash_account)s" if self.bank_cash_account else "1=1"
if self.bank_cash_account:
conditions.append(jea.against_account.like(f"%%{self.bank_cash_account}%%"))
journal_query = (
qb.from_(je)
.inner_join(jea)
.on(jea.parent == je.name)
.select(
ConstantColumn("Journal Entry").as_("reference_type"),
je.name.as_("reference_name"),
je.posting_date,
je.remark.as_("remarks"),
jea.name.as_("reference_row"),
jea[dr_or_cr].as_("amount"),
jea.is_advance,
jea.exchange_rate,
jea.account_currency.as_("currency"),
jea.cost_center.as_("cost_center"),
)
.where(
(je.docstatus == 1)
& (jea.party_type == self.party_type)
& (jea.party == self.party)
& (jea.account == self.receivable_payable_account)
& (
(jea.reference_type == "")
| (jea.reference_type.isnull())
| (jea.reference_type.isin(("Sales Order", "Purchase Order")))
)
)
.where(Criterion.all(conditions))
.orderby(je.posting_date)
)
limit = f"limit {self.payment_limit}" if self.payment_limit else " "
if self.payment_limit:
journal_query = journal_query.limit(self.payment_limit)
# nosemgrep
journal_entries = frappe.db.sql(
"""
select
"Journal Entry" as reference_type, t1.name as reference_name,
t1.posting_date, t1.remark as remarks, t2.name as reference_row,
{dr_or_cr} as amount, t2.is_advance, t2.exchange_rate,
t2.account_currency as currency, t2.cost_center as cost_center
from
`tabJournal Entry` t1, `tabJournal Entry Account` t2
where
t1.name = t2.parent and t1.docstatus = 1 and t2.docstatus = 1
and t2.party_type = %(party_type)s and t2.party = %(party)s
and t2.account = %(account)s and {dr_or_cr} > 0 {condition}
and (t2.reference_type is null or t2.reference_type = '' or
(t2.reference_type in ('Sales Order', 'Purchase Order')
and t2.reference_name is not null and t2.reference_name != ''))
and (CASE
WHEN t1.voucher_type in ('Debit Note', 'Credit Note')
THEN 1=1
ELSE {bank_account_condition}
END)
order by t1.posting_date
{limit}
""".format(
**{
"dr_or_cr": dr_or_cr,
"bank_account_condition": bank_account_condition,
"condition": condition,
"limit": limit,
}
),
{
"party_type": self.party_type,
"party": self.party,
"account": self.receivable_payable_account,
"bank_cash_account": "%%%s%%" % self.bank_cash_account,
},
as_dict=1,
)
journal_entries = journal_query.run(as_dict=True)
return list(journal_entries)
@@ -298,6 +309,7 @@ class PaymentReconciliation(Document):
min_outstanding=-(self.minimum_payment_amount) if self.minimum_payment_amount else None,
max_outstanding=-(self.maximum_payment_amount) if self.maximum_payment_amount else None,
get_payments=True,
accounting_dimensions=self.accounting_dimension_filter_conditions,
)
for inv in return_outstanding:
@@ -447,8 +459,15 @@ class PaymentReconciliation(Document):
row = self.append("allocation", {})
row.update(entry)
def update_dimension_values_in_allocated_entries(self, res):
for x in self.dimensions:
dimension = x.fieldname
if self.get(dimension):
res[dimension] = self.get(dimension)
return res
def get_allocated_entry(self, pay, inv, allocated_amount):
return frappe._dict(
res = frappe._dict(
{
"reference_type": pay.get("reference_type"),
"reference_name": pay.get("reference_name"),
@@ -464,6 +483,9 @@ class PaymentReconciliation(Document):
}
)
res = self.update_dimension_values_in_allocated_entries(res)
return res
def reconcile_allocations(self, skip_ref_details_update_for_pe=False):
adjust_allocations_for_taxes(self)
dr_or_cr = (
@@ -486,10 +508,10 @@ class PaymentReconciliation(Document):
reconciled_entry.append(payment_details)
if entry_list:
reconcile_against_document(entry_list, skip_ref_details_update_for_pe)
reconcile_against_document(entry_list, skip_ref_details_update_for_pe, self.dimensions)
if dr_or_cr_notes:
reconcile_dr_cr_note(dr_or_cr_notes, self.company)
reconcile_dr_cr_note(dr_or_cr_notes, self.company, self.dimensions)
@frappe.whitelist()
def reconcile(self):
@@ -518,7 +540,7 @@ class PaymentReconciliation(Document):
self.get_unreconciled_entries()
def get_payment_details(self, row, dr_or_cr):
return frappe._dict(
payment_details = frappe._dict(
{
"voucher_type": row.get("reference_type"),
"voucher_no": row.get("reference_name"),
@@ -541,6 +563,12 @@ class PaymentReconciliation(Document):
}
)
for x in self.dimensions:
if row.get(x.fieldname):
payment_details[x.fieldname] = row.get(x.fieldname)
return payment_details
def check_mandatory_to_fetch(self):
for fieldname in ["company", "party_type", "party", "receivable_payable_account"]:
if not self.get(fieldname):
@@ -648,6 +676,13 @@ class PaymentReconciliation(Document):
if not invoices_to_reconcile:
frappe.throw(_("No records found in Allocation table"))
def build_dimensions_filter_conditions(self):
ple = qb.DocType("Payment Ledger Entry")
for x in self.dimensions:
dimension = x.fieldname
if self.get(dimension):
self.accounting_dimension_filter_conditions.append(ple[dimension] == self.get(dimension))
def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False):
self.common_filter_conditions.clear()
self.accounting_dimension_filter_conditions.clear()
@@ -671,40 +706,30 @@ class PaymentReconciliation(Document):
if self.to_payment_date:
self.ple_posting_date_filter.append(ple.posting_date.lte(self.to_payment_date))
def get_conditions(self, get_payments=False):
condition = " and company = '{0}' ".format(self.company)
self.build_dimensions_filter_conditions()
if self.get("cost_center") and get_payments:
condition = " and cost_center = '{0}' ".format(self.cost_center)
def get_journal_filter_conditions(self):
conditions = []
je = qb.DocType("Journal Entry")
jea = qb.DocType("Journal Entry Account")
conditions.append(je.company == self.company)
condition += (
" and posting_date >= {0}".format(frappe.db.escape(self.from_payment_date))
if self.from_payment_date
else ""
)
condition += (
" and posting_date <= {0}".format(frappe.db.escape(self.to_payment_date))
if self.to_payment_date
else ""
)
if self.from_payment_date:
conditions.append(je.posting_date.gte(self.from_payment_date))
if self.to_payment_date:
conditions.append(je.posting_date.lte(self.to_payment_date))
if self.minimum_payment_amount:
condition += (
" and unallocated_amount >= {0}".format(flt(self.minimum_payment_amount))
if get_payments
else " and total_debit >= {0}".format(flt(self.minimum_payment_amount))
)
conditions.append(je.total_debit.gte(self.minimum_payment_amount))
if self.maximum_payment_amount:
condition += (
" and unallocated_amount <= {0}".format(flt(self.maximum_payment_amount))
if get_payments
else " and total_debit <= {0}".format(flt(self.maximum_payment_amount))
)
conditions.append(je.total_debit.lte(self.maximum_payment_amount))
return condition
return conditions
def reconcile_dr_cr_note(dr_cr_notes, company):
def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None):
for inv in dr_cr_notes:
voucher_type = "Credit Note" if inv.voucher_type == "Sales Invoice" else "Debit Note"
@@ -754,6 +779,15 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
}
)
# Credit Note(JE) will inherit the same dimension values as payment
dimensions_dict = frappe._dict()
if active_dimensions:
for dim in active_dimensions:
dimensions_dict[dim.fieldname] = inv.get(dim.fieldname)
jv.accounts[0].update(dimensions_dict)
jv.accounts[1].update(dimensions_dict)
jv.flags.ignore_mandatory = True
jv.flags.ignore_exchange_rate = True
jv.remark = None
@@ -787,9 +821,27 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
inv.against_voucher,
None,
inv.cost_center,
dimensions_dict,
)
@erpnext.allow_regional
def adjust_allocations_for_taxes(doc):
pass
@frappe.whitelist()
def get_queries_for_dimension_filters(company: str = None):
dimensions_with_filters = []
for d in get_dimensions()[0]:
filters = {}
meta = frappe.get_meta(d.document_type)
if meta.has_field("company") and company:
filters.update({"company": company})
if meta.is_tree:
filters.update({"is_group": 0})
dimensions_with_filters.append({"fieldname": d.fieldname, "filters": filters})
return dimensions_with_filters

View File

@@ -24,7 +24,9 @@
"difference_account",
"exchange_rate",
"currency",
"cost_center"
"accounting_dimensions_section",
"cost_center",
"dimension_col_break"
],
"fields": [
{
@@ -157,12 +159,21 @@
"fieldname": "gain_loss_posting_date",
"fieldtype": "Date",
"label": "Difference Posting Date"
},
{
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
}
],
"is_virtual": 1,
"istable": 1,
"links": [],
"modified": "2023-11-17 17:33:38.612615",
"modified": "2023-12-14 13:38:26.104150",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Allocation",

View File

@@ -169,6 +169,13 @@ class PaymentRequest(Document):
elif self.payment_channel == "Phone":
self.request_phone_payment()
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
def request_phone_payment(self):
controller = _get_payment_gateway_controller(self.payment_gateway)
request_amount = self.get_request_amount()
@@ -207,6 +214,14 @@ class PaymentRequest(Document):
self.check_if_payment_entry_exists()
self.set_as_cancelled()
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
if self.reference_doctype in advance_payment_doctypes:
# set advance payment status
ref_doc.set_total_advance_paid()
def make_invoice(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
@@ -424,6 +439,15 @@ def make_payment_request(**args):
"""Make payment request"""
args = frappe._dict(args)
if args.dt not in [
"Sales Order",
"Purchase Order",
"Sales Invoice",
"Purchase Invoice",
"POS Invoice",
"Fees",
]:
frappe.throw(_("Payment Requests cannot be created against: {0}").format(frappe.bold(args.dt)))
ref_doc = frappe.get_doc(args.dt, args.dn)
gateway_account = get_gateway_details(args) or frappe._dict()

View File

@@ -371,7 +371,7 @@ class POSInvoice(SalesInvoice):
if d.get("qty") > 0:
frappe.throw(
_(
"Row #{}: You cannot add postive quantities in a return invoice. Please remove item {} to complete the return."
"Row #{}: You cannot add positive quantities in a return invoice. Please remove item {} to complete the return."
).format(d.idx, frappe.bold(d.item_code)),
title=_("Invalid Item"),
)
@@ -793,7 +793,7 @@ def make_merge_log(invoices):
invoices = json.loads(invoices)
if len(invoices) == 0:
frappe.throw(_("Atleast one invoice has to be selected."))
frappe.throw(_("At least one invoice has to be selected."))
merge_log = frappe.new_doc("POS Invoice Merge Log")
merge_log.posting_date = getdate(nowdate())

View File

@@ -132,7 +132,7 @@ class POSProfile(Document):
if len(customer_groups) != len(set(customer_groups)):
frappe.throw(
_("Duplicate customer group found in the cutomer group table"),
_("Duplicate customer group found in the customer group table"),
title=_("Duplicate Customer Group"),
)

View File

@@ -339,7 +339,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto"
"label": "Valid Up To"
},
{
"fieldname": "col_break1",
@@ -608,7 +608,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2023-02-14 04:53:34.887358",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -193,7 +193,7 @@ class PricingRule(Document):
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
throw(_("Atleast one of the Selling or Buying must be selected"))
throw(_("At least one of the Selling or Buying must be selected"))
if not self.selling and self.applicable_for in [
"Customer",
@@ -579,12 +579,17 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
item_details[field] += pricing_rule.get(field, 0) if pricing_rule else args.get(field, 0)
@frappe.whitelist()
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None, rate=None):
from erpnext.accounts.doctype.pricing_rule.utils import (
get_applied_pricing_rules,
get_pricing_rule_items,
)
if isinstance(item_details, str):
item_details = json.loads(item_details)
item_details = frappe._dict(item_details)
for d in get_applied_pricing_rules(pricing_rules):
if not d or not frappe.db.exists("Pricing Rule", d):
continue

View File

@@ -232,7 +232,7 @@
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto"
"label": "Valid Up To"
},
{
"fieldname": "column_break_26",
@@ -278,7 +278,7 @@
}
],
"links": [],
"modified": "2021-05-06 16:20:22.039078",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Promotional Scheme",

View File

@@ -35,7 +35,7 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
super.onload();
// Ignore linked advances
this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries", "Serial and Batch Bundle"];
this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries", "Serial and Batch Bundle", "Bank Transaction"];
if(!this.frm.doc.__islocal) {
// show credit_to in print format

View File

@@ -296,6 +296,18 @@ class PurchaseInvoice(BuyingController):
self.reset_default_field_value("set_warehouse", "items", "warehouse")
self.reset_default_field_value("rejected_warehouse", "items", "rejected_warehouse")
self.reset_default_field_value("set_from_warehouse", "items", "from_warehouse")
self.set_percentage_received()
def set_percentage_received(self):
total_billed_qty = 0.0
total_received_qty = 0.0
for row in self.items:
if row.purchase_receipt and row.pr_detail and row.received_qty:
total_billed_qty += row.qty
total_received_qty += row.received_qty
if total_billed_qty and total_received_qty:
self.per_received = total_received_qty / total_billed_qty * 100
def validate_release_date(self):
if self.release_date and getdate(nowdate()) >= getdate(self.release_date):
@@ -815,9 +827,7 @@ class PurchaseInvoice(BuyingController):
"party_type": "Supplier",
"party": self.supplier,
"due_date": self.due_date,
"against_type": "Account",
"against": self.against_expense_account,
"against_link": self.against_expense_account,
"credit": base_grand_total,
"credit_in_account_currency": base_grand_total
if self.party_account_currency == self.company_currency
@@ -890,9 +900,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": warehouse_account[item.warehouse]["account"],
"against_type": "Account",
"against": warehouse_account[item.from_warehouse]["account"],
"against_link": warehouse_account[item.from_warehouse]["account"],
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
@@ -912,9 +920,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": warehouse_account[item.from_warehouse]["account"],
"against_type": "Account",
"against": warehouse_account[item.warehouse]["account"],
"against_link": warehouse_account[item.warehouse]["account"],
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
@@ -931,9 +937,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": item.expense_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"debit": flt(item.base_net_amount, item.precision("base_net_amount")),
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"cost_center": item.cost_center,
@@ -950,9 +954,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": item.expense_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"debit": warehouse_debit_amount,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"cost_center": item.cost_center,
@@ -971,9 +973,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": account,
"against_type": "Account",
"against": item.expense_account,
"against_link": item.expense_account,
"cost_center": item.cost_center,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(amount["base_amount"]),
@@ -993,9 +993,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": supplier_warehouse_account,
"against_type": "Account",
"against": item.expense_account,
"against_link": item.expense_account,
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
@@ -1050,9 +1048,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": expense_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"debit": amount,
"cost_center": item.cost_center,
"project": item.project or self.project,
@@ -1078,9 +1074,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": expense_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"debit": discrepancy_caused_by_exchange_rate_difference,
"cost_center": item.cost_center,
"project": item.project or self.project,
@@ -1093,9 +1087,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": self.get_company_default("exchange_gain_loss_account"),
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"credit": discrepancy_caused_by_exchange_rate_difference,
"cost_center": item.cost_center,
"project": item.project or self.project,
@@ -1104,17 +1096,6 @@ class PurchaseInvoice(BuyingController):
item=item,
)
)
# update gross amount of asset bought through this document
assets = frappe.db.get_all(
"Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code}
)
for asset in assets:
frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
frappe.db.set_value(
"Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)
)
if (
self.auto_accounting_for_stock
and self.is_opening == "No"
@@ -1139,10 +1120,8 @@ class PurchaseInvoice(BuyingController):
gl_entries.append(
self.get_gl_dict(
{
"account": stock_rbnb,
"against_type": "Supplier",
"account": self.stock_received_but_not_billed,
"against": self.supplier,
"against_link": self.supplier,
"debit": flt(item.item_tax_amount, item.precision("item_tax_amount")),
"remarks": self.remarks or _("Accounting Entry for Stock"),
"cost_center": self.cost_center,
@@ -1156,17 +1135,24 @@ class PurchaseInvoice(BuyingController):
item.item_tax_amount, item.precision("item_tax_amount")
)
if item.is_fixed_asset and item.landed_cost_voucher_amount:
self.update_gross_purchase_amount_for_linked_assets(item)
def update_gross_purchase_amount_for_linked_assets(self, item):
assets = frappe.db.get_all(
"Asset",
filters={"purchase_invoice": self.name, "item_code": item.item_code},
fields=["name", "asset_quantity"],
)
for asset in assets:
purchase_amount = flt(item.valuation_rate) * asset.asset_quantity
frappe.db.set_value(
"Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate) * asset.asset_quantity
)
frappe.db.set_value(
"Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate) * asset.asset_quantity
"Asset",
asset.name,
{
"gross_purchase_amount": purchase_amount,
"purchase_receipt_amount": purchase_amount,
},
)
def make_stock_adjustment_entry(
@@ -1196,9 +1182,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": cost_of_goods_sold_account,
"against_type": "Account",
"against": item.expense_account,
"against_link": item.expense_account,
"debit": stock_adjustment_amt,
"remarks": self.get("remarks") or _("Stock Adjustment"),
"cost_center": item.cost_center,
@@ -1228,9 +1212,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": tax.account_head,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
dr_or_cr: base_amount,
dr_or_cr + "_in_account_currency": base_amount
if account_currency == self.company_currency
@@ -1278,10 +1260,8 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": tax.account_head,
"against_type": "Supplier",
"cost_center": tax.cost_center,
"against": self.supplier,
"against_link": self.supplier,
"credit": applicable_amount,
"remarks": self.remarks or _("Accounting Entry for Stock"),
},
@@ -1299,9 +1279,7 @@ class PurchaseInvoice(BuyingController):
{
"account": tax.account_head,
"cost_center": tax.cost_center,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"credit": valuation_tax[tax.name],
"remarks": self.remarks or _("Accounting Entry for Stock"),
},
@@ -1316,9 +1294,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": self.unrealized_profit_loss_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"credit": flt(self.total_taxes_and_charges),
"credit_in_account_currency": flt(self.base_total_taxes_and_charges),
"cost_center": self.cost_center,
@@ -1339,9 +1315,7 @@ class PurchaseInvoice(BuyingController):
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"against_type": "Account",
"against": self.cash_bank_account,
"against_link": self.cash_bank_account,
"debit": self.base_paid_amount,
"debit_in_account_currency": self.base_paid_amount
if self.party_account_currency == self.company_currency
@@ -1362,9 +1336,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": self.cash_bank_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"credit": self.base_paid_amount,
"credit_in_account_currency": self.base_paid_amount
if bank_account_currency == self.company_currency
@@ -1388,9 +1360,7 @@ class PurchaseInvoice(BuyingController):
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"against_type": "Account",
"against": self.write_off_account,
"against_link": self.write_off_account,
"debit": self.base_write_off_amount,
"debit_in_account_currency": self.base_write_off_amount
if self.party_account_currency == self.company_currency
@@ -1410,9 +1380,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": self.write_off_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"credit": flt(self.base_write_off_amount),
"credit_in_account_currency": self.base_write_off_amount
if write_off_account_currency == self.company_currency
@@ -1439,9 +1407,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict(
{
"account": round_off_account,
"against_type": "Supplier",
"against": self.supplier,
"against_link": self.supplier,
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
"cost_center": round_off_cost_center

View File

@@ -1238,10 +1238,10 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
@change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1})
def test_gain_loss_with_advance_entry(self):
unlink_enabled = frappe.db.get_single_value(
"Accounts Settings", "unlink_payment_on_cancel_of_invoice"
"Accounts Settings", "unlink_payment_on_cancellation_of_invoice"
)
frappe.db.set_single_value("Accounts Settings", "unlink_payment_on_cancel_of_invoice", 1)
frappe.db.set_single_value("Accounts Settings", "unlink_payment_on_cancellation_of_invoice", 1)
original_account = frappe.db.get_value("Company", "_Test Company", "exchange_gain_loss_account")
frappe.db.set_value(
@@ -1432,7 +1432,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin):
pay.cancel()
frappe.db.set_single_value(
"Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
"Accounts Settings", "unlink_payment_on_cancellation_of_invoice", unlink_enabled
)
frappe.db.set_value("Company", "_Test Company", "exchange_gain_loss_account", original_account)

View File

@@ -64,6 +64,7 @@
"warehouse",
"from_warehouse",
"quality_inspection",
"add_serial_batch_bundle",
"serial_and_batch_bundle",
"serial_no",
"col_br_wh",
@@ -913,12 +914,18 @@
"fieldtype": "Link",
"label": "WIP Composite Asset",
"options": "Asset"
},
{
"depends_on": "eval:parent.update_stock === 1",
"fieldname": "add_serial_batch_bundle",
"fieldtype": "Button",
"label": "Add Serial / Batch No"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-12-25 22:00:28.043555",
"modified": "2024-01-21 19:46:25.537861",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -126,7 +126,7 @@
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"label": "Tax Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency"
},
@@ -230,7 +230,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-08-05 20:04:36.618240",
"modified": "2024-01-14 10:04:36.618240",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",
@@ -239,4 +239,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -37,8 +37,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
super.onload();
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log',
'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries",
'Serial and Batch Bundle'
'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger", "Repost Accounting Ledger", "Unreconcile Payment", "Unreconcile Payment Entries", "Serial and Batch Bundle", "Bank Transaction",
];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
@@ -898,8 +897,8 @@ frappe.ui.form.on('Sales Invoice', {
frm.events.append_time_log(frm, timesheet, 1.0);
}
});
frm.refresh_field("timesheets");
frm.trigger("calculate_timesheet_totals");
frm.refresh();
},
async get_exchange_rate(frm, from_currency, to_currency) {

View File

@@ -7,7 +7,7 @@ from frappe import _, msgprint, throw
from frappe.contacts.doctype.address.address import get_address_display
from frappe.model.mapper import get_mapped_doc
from frappe.model.utils import get_fetch_values
from frappe.utils import add_days, cint, flt, formatdate, get_link_to_form, getdate, nowdate
from frappe.utils import add_days, cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
import erpnext
from erpnext.accounts.deferred_revenue import validate_service_stop_date
@@ -1233,9 +1233,7 @@ class SalesInvoice(SellingController):
"party_type": "Customer",
"party": self.customer,
"due_date": self.due_date,
"against_type": "Account",
"against": self.against_income_account,
"against_link": self.against_income_account,
"debit": base_grand_total,
"debit_in_account_currency": base_grand_total
if self.party_account_currency == self.company_currency
@@ -1264,9 +1262,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": tax.account_head,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"credit": flt(base_amount, tax.precision("tax_amount_after_discount_amount")),
"credit_in_account_currency": (
flt(base_amount, tax.precision("base_tax_amount_after_discount_amount"))
@@ -1287,9 +1283,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": self.unrealized_profit_loss_account,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"debit": flt(self.total_taxes_and_charges),
"debit_in_account_currency": flt(self.base_total_taxes_and_charges),
"cost_center": self.cost_center,
@@ -1357,9 +1351,7 @@ class SalesInvoice(SellingController):
add_asset_activity(asset.name, _("Asset sold"))
for gle in fixed_asset_gl_entries:
gle["against_type"] = "Customer"
gle["against"] = self.customer
gle["against_link"] = self.customer
gl_entries.append(self.get_gl_dict(gle, item=item))
self.set_asset_status(asset)
@@ -1380,9 +1372,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": income_account,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (
flt(base_amount, item.precision("base_net_amount"))
@@ -1436,9 +1426,9 @@ class SalesInvoice(SellingController):
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against_type": "Account",
"against": self.loyalty_redemption_account,
"against_link": self.loyalty_redemption_account,
"against": "Expense account - "
+ cstr(self.loyalty_redemption_account)
+ " for the Loyalty Program",
"credit": self.loyalty_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
@@ -1452,9 +1442,7 @@ class SalesInvoice(SellingController):
{
"account": self.loyalty_redemption_account,
"cost_center": self.cost_center or self.loyalty_redemption_cost_center,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"debit": self.loyalty_amount,
"remark": "Loyalty Points redeemed by the customer",
},
@@ -1481,9 +1469,7 @@ class SalesInvoice(SellingController):
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against_type": "Account",
"against": payment_mode.account,
"against_link": payment_mode.account,
"credit": payment_mode.base_amount,
"credit_in_account_currency": payment_mode.base_amount
if self.party_account_currency == self.company_currency
@@ -1504,9 +1490,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": payment_mode.account,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"debit": payment_mode.base_amount,
"debit_in_account_currency": payment_mode.base_amount
if payment_mode_account_currency == self.company_currency
@@ -1530,9 +1514,7 @@ class SalesInvoice(SellingController):
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against_type": "Account",
"against": self.account_for_change_amount,
"against_link": self.account_for_change_amount,
"debit": flt(self.base_change_amount),
"debit_in_account_currency": flt(self.base_change_amount)
if self.party_account_currency == self.company_currency
@@ -1553,9 +1535,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": self.account_for_change_amount,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"credit": self.base_change_amount,
"cost_center": self.cost_center,
},
@@ -1581,9 +1561,7 @@ class SalesInvoice(SellingController):
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against_type": "Account",
"against": self.write_off_account,
"against_link": self.write_off_account,
"credit": flt(self.base_write_off_amount, self.precision("base_write_off_amount")),
"credit_in_account_currency": (
flt(self.base_write_off_amount, self.precision("base_write_off_amount"))
@@ -1603,9 +1581,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": self.write_off_account,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"debit": flt(self.base_write_off_amount, self.precision("base_write_off_amount")),
"debit_in_account_currency": (
flt(self.base_write_off_amount, self.precision("base_write_off_amount"))
@@ -1633,9 +1609,7 @@ class SalesInvoice(SellingController):
self.get_gl_dict(
{
"account": round_off_account,
"against_type": "Customer",
"against": self.customer,
"against_link": self.customer,
"credit_in_account_currency": flt(
self.rounding_adjustment, self.precision("rounding_adjustment")
),

View File

@@ -108,7 +108,7 @@
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"label": "Tax Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency"
},
@@ -218,7 +218,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-10-17 13:08:17.776528",
"modified": "2022-10-18 13:08:17.776528",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
@@ -227,4 +227,4 @@
"sort_field": "modified",
"sort_order": "ASC",
"states": []
}
}

View File

@@ -51,7 +51,7 @@
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
"options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
"options": "\nTrialing\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
"read_only": 1
},
{
@@ -267,7 +267,7 @@
"link_fieldname": "subscription"
}
],
"modified": "2023-12-28 17:20:42.687789",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",

View File

@@ -16,6 +16,7 @@ from frappe.utils.data import (
date_diff,
flt,
get_last_day,
get_link_to_form,
getdate,
nowdate,
)
@@ -77,9 +78,7 @@ class Subscription(Document):
purchase_tax_template: DF.Link | None
sales_tax_template: DF.Link | None
start_date: DF.Date | None
status: DF.Literal[
"", "Trialling", "Active", "Past Due Date", "Cancelled", "Unpaid", "Completed"
]
status: DF.Literal["", "Trialing", "Active", "Past Due Date", "Cancelled", "Unpaid", "Completed"]
submit_invoice: DF.Check
trial_period_end: DF.Date | None
trial_period_start: DF.Date | None
@@ -232,7 +231,7 @@ class Subscription(Document):
Sets the status of the `Subscription`
"""
if self.is_trialling():
self.status = "Trialling"
self.status = "Trialing"
elif (
self.status == "Active" and self.end_date and getdate(posting_date) > getdate(self.end_date)
):
@@ -317,6 +316,37 @@ class Subscription(Document):
if self.is_new():
self.set_subscription_status()
self.validate_party_billing_currency()
def validate_party_billing_currency(self):
"""
Subscription should be of the same currency as the Party's default billing currency or company default.
"""
if self.party:
party_billing_currency = frappe.get_cached_value(
self.party_type, self.party, "default_currency"
) or frappe.get_cached_value("Company", self.company, "default_currency")
plans = [x.plan for x in self.plans]
subscription_plan_currencies = frappe.db.get_all(
"Subscription Plan", filters={"name": ("in", plans)}, fields=["name", "currency"]
)
unsupported_plans = []
for x in subscription_plan_currencies:
if x.currency != party_billing_currency:
unsupported_plans.append("{0}".format(get_link_to_form("Subscription Plan", x.name)))
if unsupported_plans:
unsupported_plans = [
_(
"Below Subscription Plans are of different currency to the party default billing currency/Company currency: {0}"
).format(frappe.bold(party_billing_currency))
] + unsupported_plans
frappe.throw(
unsupported_plans, frappe.ValidationError, "Unsupported Subscription Plans", as_list=True
)
def validate_trial_period(self) -> None:
"""
Runs sanity checks on trial period dates for the `Subscription`
@@ -563,6 +593,8 @@ class Subscription(Document):
) and self.can_generate_new_invoice(posting_date):
self.generate_invoice(posting_date=posting_date)
self.update_subscription_period(add_days(self.current_invoice_end, 1))
elif posting_date and getdate(posting_date) > getdate(self.current_invoice_end):
self.update_subscription_period()
if self.cancel_at_period_end and (
getdate(posting_date) >= getdate(self.current_invoice_end)

View File

@@ -1,7 +1,7 @@
frappe.listview_settings['Subscription'] = {
get_indicator: function(doc) {
if(doc.status === 'Trialling') {
return [__("Trialling"), "green"];
if(doc.status === 'Trialing') {
return [__("Trialing"), "green"];
} else if(doc.status === 'Active') {
return [__("Active"), "green"];
} else if(doc.status === 'Completed') {

View File

@@ -46,7 +46,7 @@ class TestSubscription(FrappeTestCase):
get_date_str(subscription.current_invoice_end),
)
self.assertEqual(subscription.invoices, [])
self.assertEqual(subscription.status, "Trialling")
self.assertEqual(subscription.status, "Trialing")
def test_create_subscription_without_trial_with_correct_period(self):
subscription = create_subscription()
@@ -460,11 +460,13 @@ class TestSubscription(FrappeTestCase):
self.assertEqual(len(subscription.invoices), 1)
def test_multi_currency_subscription(self):
party = "_Test Subscription Customer"
frappe.db.set_value("Customer", party, "default_currency", "USD")
subscription = create_subscription(
start_date="2018-01-01",
generate_invoice_at="Beginning of the current subscription period",
plans=[{"plan": "_Test Plan Multicurrency", "qty": 1}],
party="_Test Subscription Customer",
plans=[{"plan": "_Test Plan Multicurrency", "qty": 1, "currency": "USD"}],
party=party,
)
subscription.process()
@@ -528,13 +530,21 @@ class TestSubscription(FrappeTestCase):
def make_plans():
create_plan(plan_name="_Test Plan Name", cost=900)
create_plan(plan_name="_Test Plan Name 2", cost=1999)
create_plan(plan_name="_Test Plan Name", cost=900, currency="INR")
create_plan(plan_name="_Test Plan Name 2", cost=1999, currency="INR")
create_plan(
plan_name="_Test Plan Name 3", cost=1999, billing_interval="Day", billing_interval_count=14
plan_name="_Test Plan Name 3",
cost=1999,
billing_interval="Day",
billing_interval_count=14,
currency="INR",
)
create_plan(
plan_name="_Test Plan Name 4", cost=20000, billing_interval="Month", billing_interval_count=3
plan_name="_Test Plan Name 4",
cost=20000,
billing_interval="Month",
billing_interval_count=3,
currency="INR",
)
create_plan(
plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD"

View File

@@ -41,7 +41,8 @@
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency"
"options": "Currency",
"reqd": 1
},
{
"fieldname": "column_break_3",
@@ -148,10 +149,11 @@
}
],
"links": [],
"modified": "2021-12-10 15:24:15.794477",
"modified": "2024-01-14 17:59:34.687977",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription Plan",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@@ -193,5 +195,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -24,7 +24,7 @@ class SubscriptionPlan(Document):
billing_interval_count: DF.Int
cost: DF.Currency
cost_center: DF.Link | None
currency: DF.Link | None
currency: DF.Link
item: DF.Link
payment_gateway: DF.Link | None
plan_name: DF.Data

View File

@@ -4,7 +4,7 @@
"doctype": "Form Tour",
"idx": 0,
"is_standard": 1,
"modified": "2021-06-29 17:00:26.145996",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -82,7 +82,7 @@
"label": "Accounts Frozen Till Date",
"parent_field": "",
"position": "Right",
"title": "Accounts Frozen Upto"
"title": "Accounts Frozen Up To"
},
{
"description": "Users with this Role are allowed to set frozen accounts and create/modify accounting entries against frozen accounts.",

View File

@@ -280,7 +280,6 @@ def check_if_in_list(gle, gl_map, dimensions=None):
"project",
"finance_book",
"voucher_no",
"against_link",
]
if dimensions:

View File

@@ -39,7 +39,7 @@ frappe.query_reports["Account Balance"] = {
{ "value": "Asset Received But Not Billed", "label": __("Asset Received But Not Billed") },
{ "value": "Bank", "label": __("Bank") },
{ "value": "Cash", "label": __("Cash") },
{ "value": "Chargeble", "label": __("Chargeble") },
{ "value": "Chargeable", "label": __("Chargeable") },
{ "value": "Capital Work in Progress", "label": __("Capital Work in Progress") },
{ "value": "Cost of Goods Sold", "label": __("Cost of Goods Sold") },
{ "value": "Depreciation", "label": __("Depreciation") },

View File

@@ -22,7 +22,7 @@ def get_columns(filters):
"fieldtype": "Link",
"fieldname": "account",
"options": "Account",
"width": 100,
"width": 200,
},
{
"label": _("Currency"),
@@ -30,7 +30,7 @@ def get_columns(filters):
"fieldname": "currency",
"options": "Currency",
"hidden": 1,
"width": 50,
"width": 100,
},
{
"label": _("Balance"),

View File

@@ -10,10 +10,8 @@
<h2 class="text-center" style="margin-top:0">{%= __(report.report_name) %}</h2>
<h4 class="text-center">
{% if (filters.customer_name) { %}
{%= filters.customer_name %}
{% } else { %}
{%= filters.customer || filters.supplier %}
{% if (filters.party) { %}
{%= __(filters.party) %}
{% } %}
</h4>
<h6 class="text-center">
@@ -141,7 +139,7 @@
<th style="width: 24%">{%= __("Reference") %}</th>
{% } %}
{% if(!filters.show_future_payments) { %}
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 20%">{%= (filters.party) ? __("Remarks"): __("Party") %}</th>
{% } %}
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
{% if(!filters.show_future_payments) { %}
@@ -158,7 +156,7 @@
<th style="width: 10%">{%= __("Remaining Balance") %}</th>
{% } %}
{% } else { %}
<th style="width: 40%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 40%">{%= (filters.party) ? __("Remarks"): __("Party") %}</th>
<th style="width: 15%">{%= __("Total Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Total Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}</th>
@@ -187,7 +185,7 @@
{% if(!filters.show_future_payments) { %}
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{% if(!(filters.party)) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}
@@ -260,7 +258,7 @@
{% if(data[i]["party"]|| "&nbsp;") { %}
{% if(!data[i]["is_total_row"]) { %}
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{% if(!(filters.party)) { %}
{%= data[i]["party"] %}
{% if(data[i]["customer_name"] && data[i]["customer_name"] != data[i]["party"]) { %}
<br> {%= data[i]["customer_name"] %}

View File

@@ -124,11 +124,11 @@ def get_provisional_profit_loss(
key = period if consolidated else period.key
effective_liability = 0.0
if liability:
effective_liability += flt(liability[-2].get(key))
effective_liability += flt(liability[0].get(key))
if equity:
effective_liability += flt(equity[-2].get(key))
effective_liability += flt(equity[0].get(key))
provisional_profit_loss[key] = flt(asset[-2].get(key)) - effective_liability
provisional_profit_loss[key] = flt(asset[0].get(key)) - effective_liability
total_row[key] = effective_liability + provisional_profit_loss[key]
if provisional_profit_loss[key]:
@@ -193,11 +193,11 @@ def get_report_summary(
for period in period_list:
key = period if consolidated else period.key
if asset:
net_asset += asset[-2].get(key)
net_asset += asset[0].get(key)
if liability:
net_liability += liability[-2].get(key)
net_liability += liability[0].get(key)
if equity:
net_equity += equity[-2].get(key)
net_equity += equity[0].get(key)
if provisional_profit_loss:
net_provisional_profit_loss += provisional_profit_loss.get(key)

View File

@@ -3,49 +3,135 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import today
from frappe.utils.data import today
from erpnext.accounts.report.balance_sheet.balance_sheet import execute
COMPANY = "_Test Company 6"
COMPANY_SHORT_NAME = "_TC6"
test_dependencies = ["Company"]
class TestBalanceSheet(FrappeTestCase):
def test_balance_sheet(self):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import (
create_sales_invoice,
make_sales_invoice,
)
from erpnext.accounts.utils import get_fiscal_year
frappe.db.sql(f"delete from `tabJournal Entry` where company='{COMPANY}'")
frappe.db.sql(f"delete from `tabGL Entry` where company='{COMPANY}'")
frappe.db.sql("delete from `tabPurchase Invoice` where company='_Test Company 6'")
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 6'")
frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 6'")
create_account("VAT Liabilities", f"Duties and Taxes - {COMPANY_SHORT_NAME}", COMPANY)
create_account("Advance VAT Paid", f"Duties and Taxes - {COMPANY_SHORT_NAME}", COMPANY)
create_account("My Bank", f"Bank Accounts - {COMPANY_SHORT_NAME}", COMPANY)
pi = make_purchase_invoice(
company="_Test Company 6",
warehouse="Finished Goods - _TC6",
expense_account="Cost of Goods Sold - _TC6",
cost_center="Main - _TC6",
qty=10,
rate=100,
# 1000 equity paid to bank account
make_journal_entry(
[
dict(
account_name="My Bank",
debit_in_account_currency=1000,
credit_in_account_currency=0,
),
dict(
account_name="Capital Stock",
debit_in_account_currency=0,
credit_in_account_currency=1000,
),
]
)
si = create_sales_invoice(
company="_Test Company 6",
debit_to="Debtors - _TC6",
income_account="Sales - _TC6",
cost_center="Main - _TC6",
qty=5,
rate=110,
# 110 income paid to bank account (100 revenue + 10 VAT)
make_journal_entry(
[
dict(
account_name="My Bank",
debit_in_account_currency=110,
credit_in_account_currency=0,
),
dict(
account_name="Sales",
debit_in_account_currency=0,
credit_in_account_currency=100,
),
dict(
account_name="VAT Liabilities",
debit_in_account_currency=0,
credit_in_account_currency=10,
),
]
)
# offset VAT Liabilities with intra-year advance payment
make_journal_entry(
[
dict(
account_name="My Bank",
debit_in_account_currency=0,
credit_in_account_currency=10,
),
dict(
account_name="Advance VAT Paid",
debit_in_account_currency=10,
credit_in_account_currency=0,
),
]
)
filters = frappe._dict(
company="_Test Company 6",
company=COMPANY,
period_start_date=today(),
period_end_date=today(),
periodicity="Yearly",
)
result = execute(filters)[1]
for account_dict in result:
if account_dict.get("account") == "Current Liabilities - _TC6":
self.assertEqual(account_dict.total, 1000)
if account_dict.get("account") == "Current Assets - _TC6":
self.assertEqual(account_dict.total, 550)
results = execute(filters)
name_and_total = {
account_dict["account_name"]: account_dict["total"]
for account_dict in results[1]
if "total" in account_dict and "account_name" in account_dict
}
self.assertNotIn("Sales", name_and_total)
self.assertIn("My Bank", name_and_total)
self.assertEqual(name_and_total["My Bank"], 1100)
self.assertIn("VAT Liabilities", name_and_total)
self.assertEqual(name_and_total["VAT Liabilities"], 10)
self.assertIn("Advance VAT Paid", name_and_total)
self.assertEqual(name_and_total["Advance VAT Paid"], -10)
self.assertIn("Duties and Taxes", name_and_total)
self.assertEqual(name_and_total["Duties and Taxes"], 0)
self.assertIn("Application of Funds (Assets)", name_and_total)
self.assertEqual(name_and_total["Application of Funds (Assets)"], 1100)
self.assertIn("Equity", name_and_total)
self.assertEqual(name_and_total["Equity"], 1000)
self.assertIn("'Provisional Profit / Loss (Credit)'", name_and_total)
self.assertEqual(name_and_total["'Provisional Profit / Loss (Credit)'"], 100)
def make_journal_entry(rows):
jv = frappe.new_doc("Journal Entry")
jv.posting_date = today()
jv.company = COMPANY
jv.user_remark = "test"
for row in rows:
row["account"] = row.pop("account_name") + " - " + COMPANY_SHORT_NAME
jv.append("accounts", row)
jv.insert()
jv.submit()
def create_account(account_name: str, parent_account: str, company: str):
if frappe.db.exists("Account", {"account_name": account_name, "company": company}):
return
acc = frappe.new_doc("Account")
acc.account_name = account_name
acc.company = COMPANY
acc.parent_account = parent_account
acc.insert()

View File

@@ -84,10 +84,6 @@ function get_filters() {
options: budget_against_options,
default: "Cost Center",
reqd: 1,
get_data: function() {
console.log(this.options);
return ["Emacs", "Rocks"];
},
on_change: function() {
frappe.query_report.set_filter_value("budget_against_filter", []);
frappe.query_report.refresh();

View File

@@ -128,7 +128,7 @@ frappe.query_reports["Consolidated Financial Statement"] = {
}
value = default_formatter(value, row, column, data);
if (!data.parent_account) {
if (data && !data.parent_account) {
value = $(`<span>${value}</span>`);
var $value = $(value).css("font-weight", "bold");

View File

@@ -376,6 +376,10 @@ class PartyLedgerSummaryReport(object):
if not income_or_expense_accounts:
# prevent empty 'in' condition
income_or_expense_accounts.append("")
else:
# escape '%' in account name
# ignoring frappe.db.escape as it replaces single quotes with double quotes
income_or_expense_accounts = [x.replace("%", "%%") for x in income_or_expense_accounts]
accounts_query = (
qb.from_(gl)

View File

@@ -8,17 +8,7 @@ import re
import frappe
from frappe import _
from frappe.utils import (
add_days,
add_months,
cint,
cstr,
flt,
formatdate,
get_first_day,
getdate,
today,
)
from frappe.utils import add_days, add_months, cint, cstr, flt, formatdate, get_first_day, getdate
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
@@ -53,8 +43,6 @@ def get_period_list(
year_start_date = getdate(period_start_date)
year_end_date = getdate(period_end_date)
year_end_date = getdate(today()) if year_end_date > getdate(today()) else year_end_date
months_to_add = {"Yearly": 12, "Half-Yearly": 6, "Quarterly": 3, "Monthly": 1}[periodicity]
period_list = []

View File

@@ -203,7 +203,7 @@ def get_gl_entries(filters, accounting_dimensions):
voucher_type, voucher_subtype, voucher_no, {dimension_fields}
cost_center, project, {transaction_currency_fields}
against_voucher_type, against_voucher, account_currency,
against_link, against, is_opening, creation {select_fields}
against, is_opening, creation {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
{order_by_statement}
@@ -398,7 +398,6 @@ def initialize_gle_map(gl_entries, filters):
group_by = group_by_field(filters.get("group_by"))
for gle in gl_entries:
gle.against = gle.get("against_link") or gle.get("against")
gle_map.setdefault(gle.get(group_by), _dict(totals=get_totals_dict(), entries=[]))
return gle_map
@@ -449,6 +448,10 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
for gle in gl_entries:
group_by_value = gle.get(group_by)
gle.voucher_type = _(gle.voucher_type)
gle.voucher_subtype = _(gle.voucher_subtype)
gle.against_voucher_type = _(gle.against_voucher_type)
gle.remarks = _(gle.remarks)
gle.party_type = _(gle.party_type)
if gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries):
if not group_by_voucher_consolidated:

View File

@@ -134,7 +134,7 @@ def get_revenue(data, period_list, include_in_gross=1):
def remove_parent_with_no_child(data):
data_to_be_removed = False
for parent in data:
for parent in list(data):
if "is_group" in parent and parent.get("is_group") == 1:
have_child = False
for child in data:

View File

@@ -59,7 +59,21 @@ frappe.query_reports["Item-wise Sales Register"] = {
"fieldname": "group_by",
"fieldtype": "Select",
"options": ["Customer Group", "Customer", "Item Group", "Item", "Territory", "Invoice"]
}
},
{
"fieldname": "income_account",
"label": __("Income Account"),
"fieldtype": "Link",
"options": "Account",
get_query: () => {
let company = frappe.query_report.get_filter_value('company');
return {
filters: {
'company': company,
}
};
}
},
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);

View File

@@ -83,9 +83,7 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions=
"company": d.company,
"sales_order": d.sales_order,
"delivery_note": d.delivery_note,
"income_account": d.unrealized_profit_loss_account
if d.is_internal_customer == 1
else d.income_account,
"income_account": get_income_account(d),
"cost_center": d.cost_center,
"stock_qty": d.stock_qty,
"stock_uom": d.stock_uom,
@@ -150,6 +148,15 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions=
return columns, data, None, None, None, skip_total_row
def get_income_account(row):
if row.enable_deferred_revenue:
return row.deferred_revenue_account
elif row.is_internal_customer == 1:
return row.unrealized_profit_loss_account
else:
return row.income_account
def get_columns(additional_table_columns, filters):
columns = []
@@ -358,6 +365,13 @@ def get_conditions(filters, additional_conditions=None):
if filters.get("item_group"):
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
if filters.get("income_account"):
conditions += """
and (ifnull(`tabSales Invoice Item`.income_account, '') = %(income_account)s
or ifnull(`tabSales Invoice Item`.deferred_revenue_account, '') = %(income_account)s
or ifnull(`tabSales Invoice`.unrealized_profit_loss_account, '') = %(income_account)s)
"""
if not filters.get("group_by"):
conditions += (
"ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
@@ -399,6 +413,7 @@ def get_items(filters, additional_query_columns, additional_conditions=None):
`tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group,
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
`tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
`tabSales Invoice Item`.enable_deferred_revenue, `tabSales Invoice Item`.deferred_revenue_account,
`tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
`tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,

View File

@@ -46,12 +46,10 @@ def get_result(
out = []
for name, details in gle_map.items():
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
bill_no, bill_date = "", ""
tax_withholding_category = tax_category_map.get(name)
rate = tax_rate_map.get(tax_withholding_category)
for entry in details:
tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
tax_withholding_category, rate = None, None
bill_no, bill_date = "", ""
party = entry.party or entry.against
posting_date = entry.posting_date
voucher_type = entry.voucher_type
@@ -61,12 +59,19 @@ def get_result(
if party_list:
party = party_list[0]
if not tax_withholding_category:
tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category")
rate = tax_rate_map.get(tax_withholding_category)
if entry.account in tds_accounts:
if entry.account in tds_accounts.keys():
tax_amount += entry.credit - entry.debit
# infer tax withholding category from the account if it's the single account for this category
tax_withholding_category = tds_accounts.get(entry.account)
rate = tax_rate_map.get(tax_withholding_category)
# or else the consolidated value from the voucher document
if not tax_withholding_category:
# or else from the party default
tax_withholding_category = tax_category_map.get(name)
rate = tax_rate_map.get(tax_withholding_category)
if not tax_withholding_category:
tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category")
rate = tax_rate_map.get(tax_withholding_category)
if net_total_map.get(name):
if voucher_type == "Journal Entry" and tax_amount and rate:
@@ -80,41 +85,41 @@ def get_result(
else:
total_amount += entry.credit
if tax_amount:
if party_map.get(party, {}).get("party_type") == "Supplier":
party_name = "supplier_name"
party_type = "supplier_type"
else:
party_name = "customer_name"
party_type = "customer_type"
if tax_amount:
if party_map.get(party, {}).get("party_type") == "Supplier":
party_name = "supplier_name"
party_type = "supplier_type"
else:
party_name = "customer_name"
party_type = "customer_type"
row = {
"pan"
if frappe.db.has_column(filters.party_type, "pan")
else "tax_id": party_map.get(party, {}).get("pan"),
"party": party_map.get(party, {}).get("name"),
}
if filters.naming_series == "Naming Series":
row.update({"party_name": party_map.get(party, {}).get(party_name)})
row.update(
{
"section_code": tax_withholding_category or "",
"entity_type": party_map.get(party, {}).get(party_type),
"rate": rate,
"total_amount": total_amount,
"grand_total": grand_total,
"base_total": base_total,
"tax_amount": tax_amount,
"transaction_date": posting_date,
"transaction_type": voucher_type,
"ref_no": name,
"supplier_invoice_no": bill_no,
"supplier_invoice_date": bill_date,
row = {
"pan"
if frappe.db.has_column(filters.party_type, "pan")
else "tax_id": party_map.get(party, {}).get("pan"),
"party": party_map.get(party, {}).get("name"),
}
)
out.append(row)
if filters.naming_series == "Naming Series":
row.update({"party_name": party_map.get(party, {}).get(party_name)})
row.update(
{
"section_code": tax_withholding_category or "",
"entity_type": party_map.get(party, {}).get(party_type),
"rate": rate,
"total_amount": total_amount,
"grand_total": grand_total,
"base_total": base_total,
"tax_amount": tax_amount,
"transaction_date": posting_date,
"transaction_type": voucher_type,
"ref_no": name,
"supplier_invoice_no": bill_no,
"supplier_invoice_date": bill_date,
}
)
out.append(row)
out.sort(key=lambda x: x["section_code"])
@@ -282,11 +287,20 @@ def get_tds_docs(filters):
journal_entry_party_map = frappe._dict()
bank_accounts = frappe.get_all("Account", {"is_group": 0, "account_type": "Bank"}, pluck="name")
tds_accounts = frappe.get_all(
"Tax Withholding Account", {"company": filters.get("company")}, pluck="account"
_tds_accounts = frappe.get_all(
"Tax Withholding Account",
{"company": filters.get("company")},
["account", "parent"],
)
tds_accounts = {}
for tds_acc in _tds_accounts:
# if it turns out not to be the only tax withholding category, then don't include in the map
if tds_accounts.get(tds_acc["account"]):
tds_accounts[tds_acc["account"]] = None
else:
tds_accounts[tds_acc["account"]] = tds_acc["parent"]
tds_docs = get_tds_docs_query(filters, bank_accounts, tds_accounts).run(as_dict=True)
tds_docs = get_tds_docs_query(filters, bank_accounts, list(tds_accounts.keys())).run(as_dict=True)
for d in tds_docs:
if d.voucher_type == "Purchase Invoice":

View File

@@ -368,7 +368,7 @@ def filter_invoices_based_on_dimensions(filters, query, parent_doc):
dimension.document_type, filters.get(dimension.fieldname)
)
fieldname = dimension.fieldname
query = query.where(parent_doc[fieldname] == filters.fieldname)
query = query.where(parent_doc[fieldname].isin(filters[fieldname]))
return query

View File

@@ -23,6 +23,10 @@ class TestUtils(unittest.TestCase):
super(TestUtils, cls).setUpClass()
make_test_objects("Address", ADDRESS_RECORDS)
@classmethod
def tearDownClass(cls):
frappe.db.rollback()
def test_get_party_shipping_address(self):
address = get_party_shipping_address("Customer", "_Test Customer 1")
self.assertEqual(address, "_Test Billing Address 2 Title-Billing")
@@ -126,6 +130,38 @@ class TestUtils(unittest.TestCase):
self.assertEqual(len(payment_entry.references), 1)
self.assertEqual(payment_entry.difference_amount, 0)
def test_naming_series_variable_parsing(self):
"""
Tests parsing utility used by Naming Series Variable hook for FY
"""
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.utils import nowdate
from erpnext.accounts.utils import get_fiscal_year
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
# Configure Supplier Naming in Buying Settings
frappe.db.set_default("supp_master_name", "Auto Name")
# Configure Autoname in Supplier DocType
make_property_setter(
"Supplier", None, "naming_rule", "Expression", "Data", for_doctype="Doctype"
)
make_property_setter(
"Supplier", None, "autoname", "SUP-.FY.-.#####", "Data", for_doctype="Doctype"
)
fiscal_year = get_fiscal_year(nowdate())[0]
# Create Supplier
supplier = create_supplier()
# Check Naming Series in generated Supplier ID
doc_name = supplier.name.split("-")
self.assertEqual(len(doc_name), 3)
self.assertSequenceEqual(doc_name[0:2], ("SUP", fiscal_year))
frappe.db.set_default("supp_master_name", "Supplier Name")
ADDRESS_RECORDS = [
{

View File

@@ -240,7 +240,6 @@ def get_balance_on(
cond.append("""gle.cost_center = %s """ % (frappe.db.escape(cost_center, percent=False),))
if account:
if not (frappe.flags.ignore_account_permission or ignore_account_permission):
acc.check_permission("read")
@@ -286,18 +285,22 @@ def get_balance_on(
cond.append("""gle.company = %s """ % (frappe.db.escape(company, percent=False)))
if account or (party_type and party) or account_type:
precision = get_currency_precision()
if in_account_currency:
select_field = "sum(debit_in_account_currency) - sum(credit_in_account_currency)"
select_field = (
"sum(round(debit_in_account_currency, %s)) - sum(round(credit_in_account_currency, %s))"
)
else:
select_field = "sum(debit) - sum(credit)"
select_field = "sum(round(debit, %s)) - sum(round(credit, %s))"
bal = frappe.db.sql(
"""
SELECT {0}
FROM `tabGL Entry` gle
WHERE {1}""".format(
select_field, " and ".join(cond)
)
),
(precision, precision),
)[0][0]
# if bal is None, return 0
return flt(bal)
@@ -453,7 +456,19 @@ def add_cc(args=None):
return cc.name
def reconcile_against_document(args, skip_ref_details_update_for_pe=False): # nosemgrep
def _build_dimensions_dict_for_exc_gain_loss(
entry: dict | object = None, active_dimensions: list = None
):
dimensions_dict = frappe._dict()
if entry and active_dimensions:
for dim in active_dimensions:
dimensions_dict[dim.fieldname] = entry.get(dim.fieldname)
return dimensions_dict
def reconcile_against_document(
args, skip_ref_details_update_for_pe=False, active_dimensions=None
): # nosemgrep
"""
Cancel PE or JV, Update against document, split if required and resubmit
"""
@@ -482,6 +497,8 @@ def reconcile_against_document(args, skip_ref_details_update_for_pe=False): # n
check_if_advance_entry_modified(entry)
validate_allocated_amount(entry)
dimensions_dict = _build_dimensions_dict_for_exc_gain_loss(entry, active_dimensions)
# update ref in advance entry
if voucher_type == "Journal Entry":
referenced_row = update_reference_in_journal_entry(entry, doc, do_not_save=False)
@@ -489,10 +506,14 @@ def reconcile_against_document(args, skip_ref_details_update_for_pe=False): # n
# amount and account in args
# referenced_row is used to deduplicate gain/loss journal
entry.update({"referenced_row": referenced_row})
doc.make_exchange_gain_loss_journal([entry])
doc.make_exchange_gain_loss_journal([entry], dimensions_dict)
else:
referenced_row = update_reference_in_payment_entry(
entry, doc, do_not_save=True, skip_ref_details_update_for_pe=skip_ref_details_update_for_pe
entry,
doc,
do_not_save=True,
skip_ref_details_update_for_pe=skip_ref_details_update_for_pe,
dimensions_dict=dimensions_dict,
)
doc.save(ignore_permissions=True)
@@ -600,7 +621,10 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
jv_detail = journal_entry.get("accounts", {"name": d["voucher_detail_no"]})[0]
# Update Advance Paid in SO/PO since they might be getting unlinked
if jv_detail.get("reference_type") in ("Sales Order", "Purchase Order"):
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
if jv_detail.get("reference_type") in advance_payment_doctypes:
frappe.get_doc(jv_detail.reference_type, jv_detail.reference_name).set_total_advance_paid()
if flt(d["unadjusted_amount"]) - flt(d["allocated_amount"]) != 0:
@@ -642,7 +666,6 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
new_row.set("reference_name", d["against_voucher"])
new_row.against_account = cstr(jv_detail.against_account)
new_row.against_account_link = cstr(jv_detail.against_account)
new_row.is_advance = cstr(jv_detail.is_advance)
new_row.docstatus = 1
@@ -655,7 +678,7 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
def update_reference_in_payment_entry(
d, payment_entry, do_not_save=False, skip_ref_details_update_for_pe=False
d, payment_entry, do_not_save=False, skip_ref_details_update_for_pe=False, dimensions_dict=None
):
reference_details = {
"reference_doctype": d.against_voucher_type,
@@ -668,13 +691,17 @@ def update_reference_in_payment_entry(
else payment_entry.get_exchange_rate(),
"exchange_gain_loss": d.difference_amount,
"account": d.account,
"dimensions": d.dimensions,
}
if d.voucher_detail_no:
existing_row = payment_entry.get("references", {"name": d["voucher_detail_no"]})[0]
# Update Advance Paid in SO/PO since they are getting unlinked
if existing_row.get("reference_doctype") in ("Sales Order", "Purchase Order"):
advance_payment_doctypes = frappe.get_hooks(
"advance_payment_customer_doctypes"
) + frappe.get_hooks("advance_payment_supplier_doctypes")
if existing_row.get("reference_doctype") in advance_payment_doctypes:
frappe.get_doc(
existing_row.reference_doctype, existing_row.reference_name
).set_total_advance_paid()
@@ -700,8 +727,9 @@ def update_reference_in_payment_entry(
if not skip_ref_details_update_for_pe:
payment_entry.set_missing_ref_details()
payment_entry.set_amounts()
payment_entry.make_exchange_gain_loss_journal(
frappe._dict({"difference_posting_date": d.difference_posting_date})
frappe._dict({"difference_posting_date": d.difference_posting_date}), dimensions_dict
)
if not do_not_save:
@@ -1275,12 +1303,12 @@ def get_autoname_with_number(number_value, doc_title, company):
def parse_naming_series_variable(doc, variable):
if variable == "FY":
if doc:
date = doc.get("posting_date") or doc.get("transaction_date")
date = doc.get("posting_date") or doc.get("transaction_date") or getdate()
company = doc.get("company")
else:
date = getdate()
company = None
return get_fiscal_year(date=date, company=company).name
return get_fiscal_year(date=date, company=company)[0]
@frappe.whitelist()
@@ -2043,6 +2071,7 @@ def create_gain_loss_journal(
ref2_dn,
ref2_detail_no,
cost_center,
dimensions,
) -> str:
journal_entry = frappe.new_doc("Journal Entry")
journal_entry.voucher_type = "Exchange Gain Or Loss"
@@ -2076,7 +2105,8 @@ def create_gain_loss_journal(
dr_or_cr + "_in_account_currency": 0,
}
)
if dimensions:
journal_account.update(dimensions)
journal_entry.append("accounts", journal_account)
journal_account = frappe._dict(
@@ -2092,7 +2122,8 @@ def create_gain_loss_journal(
reverse_dr_or_cr: abs(exc_gain_loss),
}
)
if dimensions:
journal_account.update(dimensions)
journal_entry.append("accounts", journal_account)
journal_entry.save()

View File

@@ -5,7 +5,7 @@
"label": "Profit and Loss"
}
],
"content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Banking\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"nDhfcJYbKH\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"9k1rDm2C0l\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Tax Masters\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Banking\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}}]",
"creation": "2020-03-02 15:41:59.515192",
"custom_blocks": [],
"docstatus": 0,
@@ -14,562 +14,10 @@
"hide_custom": 0,
"icon": "accounting",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Accounting",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Accounting Masters",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Company",
"link_count": 0,
"link_to": "Company",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Chart of Accounts",
"link_count": 0,
"link_to": "Account",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Settings",
"link_count": 0,
"link_to": "Accounts Settings",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Fiscal Year",
"link_count": 0,
"link_to": "Fiscal Year",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Accounting Dimension",
"link_count": 0,
"link_to": "Accounting Dimension",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Finance Book",
"link_count": 0,
"link_to": "Finance Book",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Accounting Period",
"link_count": 0,
"link_to": "Accounting Period",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Term",
"link_count": 0,
"link_to": "Payment Term",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "General Ledger",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry",
"link_count": 0,
"link_to": "Journal Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry Template",
"link_count": 0,
"link_to": "Journal Entry Template",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "General Ledger",
"link_count": 0,
"link_to": "General Ledger",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Customer Ledger Summary",
"link_count": 0,
"link_to": "Customer Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Supplier Ledger Summary",
"link_count": 0,
"link_to": "Supplier Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Receivable",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Sales Invoice",
"link_count": 0,
"link_to": "Sales Invoice",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Customer",
"link_count": 0,
"link_to": "Customer",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Request",
"link_count": 0,
"link_to": "Payment Request",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable",
"link_count": 0,
"link_to": "Accounts Receivable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable Summary",
"link_count": 0,
"link_to": "Accounts Receivable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Register",
"link_count": 0,
"link_to": "Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Item-wise Sales Register",
"link_count": 0,
"link_to": "Item-wise Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Order Analysis",
"link_count": 0,
"link_to": "Sales Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Delivered Items To Be Billed",
"link_count": 0,
"link_to": "Delivered Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Payable",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Purchase Invoice",
"link_count": 0,
"link_to": "Purchase Invoice",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Supplier",
"link_count": 0,
"link_to": "Supplier",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Payable",
"link_count": 0,
"link_to": "Accounts Payable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Payable Summary",
"link_count": 0,
"link_to": "Accounts Payable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Register",
"link_count": 0,
"link_to": "Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Item-wise Purchase Register",
"link_count": 0,
"link_to": "Item-wise Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Order",
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Order Analysis",
"link_count": 0,
"link_to": "Purchase Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Received Items To Be Billed",
"link_count": 0,
"link_to": "Received Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Trial Balance for Party",
"link_count": 0,
"link_to": "Trial Balance for Party",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Journal Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Payment Period Based On Invoice Date",
"link_count": 0,
"link_to": "Payment Period Based On Invoice Date",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Partners Commission",
"link_count": 0,
"link_to": "Sales Partners Commission",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Customer",
"hidden": 0,
"is_query_report": 1,
"label": "Customer Credit Balance",
"link_count": 0,
"link_to": "Customer Credit Balance",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Payment Summary",
"link_count": 0,
"link_to": "Sales Payment Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Address",
"hidden": 0,
"is_query_report": 1,
"label": "Address And Contacts",
"link_count": 0,
"link_to": "Address And Contacts",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "UAE VAT 201",
"link_count": 0,
"link_to": "UAE VAT 201",
"link_type": "Report",
"onboard": 0,
"only_for": "United Arab Emirates",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Financial Statements",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Trial Balance",
"link_count": 0,
"link_to": "Trial Balance",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Profit and Loss Statement",
"link_count": 0,
"link_to": "Profit and Loss Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Balance Sheet",
"link_count": 0,
"link_to": "Balance Sheet",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Cash Flow",
"link_count": 0,
"link_to": "Cash Flow",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Consolidated Financial Statement",
"link_count": 0,
"link_to": "Consolidated Financial Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -611,102 +59,6 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Settings",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Gateway Account",
"link_count": 0,
"link_to": "Payment Gateway Account",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Terms and Conditions Template",
"link_count": 0,
"link_to": "Terms and Conditions",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Mode of Payment",
"link_count": 0,
"link_to": "Mode of Payment",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank",
"link_count": 0,
"link_to": "Bank",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Account",
"link_count": 0,
"link_to": "Bank Account",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Clearance",
"link_count": 0,
"link_to": "Bank Clearance",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Reconciliation Tool",
"link_count": 0,
"link_to": "Bank Reconciliation Tool",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Bank Reconciliation Statement",
"link_count": 0,
"link_to": "Bank Reconciliation Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -918,8 +270,83 @@
{
"hidden": 0,
"is_query_report": 0,
"label": "Taxes",
"label": "Banking",
"link_count": 6,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank",
"link_count": 0,
"link_to": "Bank",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Account",
"link_count": 0,
"link_to": "Bank Account",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Clearance",
"link_count": 0,
"link_to": "Bank Clearance",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Reconciliation Tool",
"link_count": 0,
"link_to": "Bank Reconciliation Tool",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Bank Reconciliation Statement",
"link_count": 0,
"link_to": "Bank Reconciliation Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Plaid Settings",
"link_count": 0,
"link_to": "Plaid Settings",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Tax Masters",
"link_count": 7,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
@@ -1003,60 +430,8 @@
{
"hidden": 0,
"is_query_report": 0,
"label": "Profitability",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Gross Profit",
"link_count": 0,
"link_to": "Gross Profit",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Profitability Analysis",
"link_count": 0,
"link_to": "Profitability Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Invoice Trends",
"link_count": 0,
"link_to": "Sales Invoice Trends",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Invoice Trends",
"link_count": 0,
"link_to": "Purchase Invoice Trends",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Banking",
"link_count": 6,
"label": "Accounting Masters",
"link_count": 8,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
@@ -1065,9 +440,31 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank",
"label": "Company",
"link_count": 0,
"link_to": "Bank",
"link_to": "Company",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Chart of Accounts",
"link_count": 0,
"link_to": "Account",
"link_type": "DocType",
"onboard": 1,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Settings",
"link_count": 0,
"link_to": "Accounts Settings",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -1076,9 +473,9 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Account",
"label": "Fiscal Year",
"link_count": 0,
"link_to": "Bank Account",
"link_to": "Fiscal Year",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -1087,9 +484,9 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Clearance",
"label": "Accounting Dimension",
"link_count": 0,
"link_to": "Bank Clearance",
"link_to": "Accounting Dimension",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -1098,36 +495,98 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Bank Reconciliation Tool",
"label": "Finance Book",
"link_count": 0,
"link_to": "Bank Reconciliation Tool",
"link_to": "Finance Book",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"dependencies": "",
"hidden": 0,
"is_query_report": 1,
"label": "Bank Reconciliation Statement",
"is_query_report": 0,
"label": "Accounting Period",
"link_count": 0,
"link_to": "Bank Reconciliation Statement",
"link_type": "Report",
"link_to": "Accounting Period",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Term",
"link_count": 0,
"link_to": "Payment Term",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Plaid Settings",
"label": "Payments",
"link_count": 5,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Plaid Settings",
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry",
"link_count": 0,
"link_to": "Journal Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry Template",
"link_count": 0,
"link_to": "Journal Entry Template",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Terms and Conditions",
"link_count": 0,
"link_to": "Terms and Conditions",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Mode of Payment",
"link_count": 0,
"link_to": "Mode of Payment",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2024-01-02 15:21:09.895531",
"modified": "2024-01-18 22:15:40.941711",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",

View File

@@ -0,0 +1,277 @@
{
"charts": [],
"content": "[{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"Ledgers\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"creation": "2024-01-05 16:09:16.766939",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "file",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Financial Reports",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Profitability",
"link_count": 0,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Gross Profit",
"link_count": 0,
"link_to": "Gross Profit",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Profitability Analysis",
"link_count": 0,
"link_to": "Profitability Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Invoice Trends",
"link_count": 0,
"link_to": "Sales Invoice Trends",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Purchase Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Purchase Invoice Trends",
"link_count": 0,
"link_to": "Purchase Invoice Trends",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Financial Statements",
"link_count": 5,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Trial Balance",
"link_count": 0,
"link_to": "Trial Balance",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Profit and Loss Statement",
"link_count": 0,
"link_to": "Profit and Loss Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Balance Sheet",
"link_count": 0,
"link_to": "Balance Sheet",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Cash Flow",
"link_count": 0,
"link_to": "Cash Flow",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Consolidated Financial Statement",
"link_count": 0,
"link_to": "Consolidated Financial Statement",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Ledgers",
"link_count": 3,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "General Ledger",
"link_count": 0,
"link_to": "General Ledger",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Customer Ledger Summary",
"link_count": 0,
"link_to": "Customer Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Supplier Ledger Summary",
"link_count": 0,
"link_to": "Supplier Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Other Reports",
"link_count": 7,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Trial Balance for Party",
"link_count": 0,
"link_to": "Trial Balance for Party",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Journal Entry",
"hidden": 0,
"is_query_report": 1,
"label": "Payment Period Based On Invoice Date",
"link_count": 0,
"link_to": "Payment Period Based On Invoice Date",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Partners Commission",
"link_count": 0,
"link_to": "Sales Partners Commission",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Customer",
"hidden": 0,
"is_query_report": 1,
"label": "Customer Credit Balance",
"link_count": 0,
"link_to": "Customer Credit Balance",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Payment Summary",
"link_count": 0,
"link_to": "Sales Payment Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Address",
"hidden": 0,
"is_query_report": 1,
"label": "Address And Contacts",
"link_count": 0,
"link_to": "Address And Contacts",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "UAE VAT 201",
"link_count": 0,
"link_to": "UAE VAT 201",
"link_type": "Report",
"onboard": 0,
"only_for": "United Arab Emirates",
"type": "Link"
}
],
"modified": "2024-01-18 22:13:07.596844",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Financial Reports",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 5.0,
"shortcuts": [],
"title": "Financial Reports"
}

View File

@@ -0,0 +1,204 @@
{
"charts": [],
"content": "[{\"id\":\"rMMsfn2eB4\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Shortcuts</b></span>\",\"col\":12}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Payable\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"jAcOH-cC-Q\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"7dj93PEUjW\",\"type\":\"card\",\"data\":{\"card_name\":\"Invoicing\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"9yseIkdG50\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2024-01-05 15:29:11.144373",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "arrow-left",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Payables",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Invoicing",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Purchase Invoice",
"link_count": 0,
"link_to": "Purchase Invoice",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Supplier",
"link_count": 0,
"link_to": "Supplier",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payments",
"link_count": 3,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Journal Entry",
"link_count": 0,
"link_to": "Journal Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 7,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Payable",
"link_count": 0,
"link_to": "Accounts Payable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Accounts Payable Summary",
"link_count": 0,
"link_to": "Accounts Payable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Purchase Register",
"link_count": 0,
"link_to": "Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Item-wise Purchase Register",
"link_count": 0,
"link_to": "Item-wise Purchase Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Purchase Order Analysis",
"link_count": 0,
"link_to": "Purchase Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Received Items To Be Billed",
"link_count": 0,
"link_to": "Received Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Supplier Ledger Summary",
"link_count": 0,
"link_to": "Supplier Ledger Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
}
],
"modified": "2024-01-18 22:09:46.221549",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payables",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 3.0,
"shortcuts": [
{
"doc_view": "",
"label": "Accounts Payable",
"link_to": "Accounts Payable",
"type": "Report"
},
{
"doc_view": "",
"label": "Purchase Invoice",
"link_to": "Purchase Invoice",
"type": "DocType"
},
{
"doc_view": "",
"label": "Journal Entry",
"link_to": "Journal Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Payment Entry",
"link_to": "Payment Entry",
"type": "DocType"
}
],
"title": "Payables"
}

View File

@@ -0,0 +1,254 @@
{
"charts": [],
"content": "[{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Shortcuts</b></span>\",\"col\":12}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"5yHldR0JNk\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"POS Invoice\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"ILlIxJuexy\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Cost Center\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"jLgv00c6ek\",\"type\":\"card\",\"data\":{\"card_name\":\"Invoicing\",\"col\":4}},{\"id\":\"npwfXlz0u1\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"am70C27Jrb\",\"type\":\"card\",\"data\":{\"card_name\":\"Dunning\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}}]",
"creation": "2024-01-05 15:29:21.084241",
"custom_blocks": [],
"docstatus": 0,
"doctype": "Workspace",
"for_user": "",
"hide_custom": 0,
"icon": "arrow-right",
"idx": 0,
"indicator_color": "",
"is_hidden": 0,
"label": "Receivables",
"links": [
{
"hidden": 0,
"is_query_report": 0,
"label": "Invoicing",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Invoice",
"link_count": 0,
"link_to": "Sales Invoice",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Customer",
"link_count": 0,
"link_to": "Customer",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payments",
"link_count": 4,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Entry",
"link_count": 0,
"link_to": "Payment Entry",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Request",
"link_count": 0,
"link_to": "Payment Request",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Reconciliation",
"link_count": 0,
"link_to": "Payment Reconciliation",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Payment Gateway Account",
"link_count": 0,
"link_to": "Payment Gateway Account",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning",
"link_count": 2,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning",
"link_count": 0,
"link_to": "Dunning",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Dunning Type",
"link_count": 0,
"link_to": "Dunning Type",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Reports",
"link_count": 6,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable",
"link_count": 0,
"link_to": "Accounts Receivable",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Accounts Receivable Summary",
"link_count": 0,
"link_to": "Accounts Receivable Summary",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Register",
"link_count": 0,
"link_to": "Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Item-wise Sales Register",
"link_count": 0,
"link_to": "Item-wise Sales Register",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Sales Order Analysis",
"link_count": 0,
"link_to": "Sales Order Analysis",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{
"dependencies": "Sales Invoice",
"hidden": 0,
"is_query_report": 1,
"label": "Delivered Items To Be Billed",
"link_count": 0,
"link_to": "Delivered Items To Be Billed",
"link_type": "Report",
"onboard": 0,
"type": "Link"
}
],
"modified": "2024-01-18 22:11:51.474477",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Receivables",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 4.0,
"shortcuts": [
{
"color": "Grey",
"doc_view": "List",
"label": "POS Invoice",
"link_to": "POS Invoice",
"stats_filter": "[]",
"type": "DocType"
},
{
"color": "Grey",
"doc_view": "List",
"label": "Cost Center",
"link_to": "Cost Center",
"type": "DocType"
},
{
"doc_view": "",
"label": "Sales Invoice",
"link_to": "Sales Invoice",
"stats_filter": "[]",
"type": "DocType"
},
{
"doc_view": "",
"label": "Journal Entry",
"link_to": "Journal Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Payment Entry",
"link_to": "Payment Entry",
"type": "DocType"
},
{
"doc_view": "",
"label": "Accounts Receivable",
"link_to": "Accounts Receivable",
"type": "Report"
}
],
"title": "Receivables"
}

View File

@@ -571,10 +571,16 @@ frappe.ui.form.on('Asset', {
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount);
item.asset_location && frm.set_value('location', item.asset_location);
var is_grouped_asset = frappe.db.get_value('Item', item.item_code, 'is_grouped_asset');
var asset_quantity = is_grouped_asset ? item.qty : 1;
var purchase_amount = flt(item.valuation_rate * asset_quantity, precision('gross_purchase_amount'));
frm.set_value('gross_purchase_amount', purchase_amount);
frm.set_value('purchase_receipt_amount', purchase_amount);
frm.set_value('asset_quantity', asset_quantity);
frm.set_value('cost_center', item.cost_center || purchase_doc.cost_center);
if(item.asset_location) { frm.set_value('location', item.asset_location); }
},
set_depreciation_rate: function(frm, row) {

View File

@@ -202,8 +202,7 @@
"fieldname": "purchase_date",
"fieldtype": "Date",
"label": "Purchase Date",
"mandatory_depends_on": "eval:!doc.is_existing_asset",
"read_only": 1,
"mandatory_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
},
{
@@ -590,7 +589,7 @@
"link_fieldname": "target_asset"
}
],
"modified": "2024-01-05 17:36:53.131512",
"modified": "2024-01-15 17:35:49.226603",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@@ -162,6 +162,7 @@ class Asset(AccountsController):
def on_cancel(self):
self.validate_cancellation()
self.cancel_movement_entries()
self.cancel_capitalization()
self.delete_depreciation_entries()
cancel_asset_depr_schedules(self)
self.set_status()
@@ -517,6 +518,13 @@ class Asset(AccountsController):
movement = frappe.get_doc("Asset Movement", movement.get("name"))
movement.cancel()
def cancel_capitalization(self):
if self.capitalized_in:
self.db_set("capitalized_in", None)
asset_capitalization = frappe.get_doc("Asset Capitalization", self.capitalized_in)
if asset_capitalization.docstatus == 1:
asset_capitalization.cancel()
def delete_depreciation_entries(self):
if self.calculate_depreciation:
for row in self.get("finance_books"):
@@ -697,9 +705,7 @@ class Asset(AccountsController):
self.get_gl_dict(
{
"account": cwip_account,
"against_type": "Account",
"against": fixed_asset_account,
"against_link": fixed_asset_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"credit": self.purchase_receipt_amount,
@@ -714,9 +720,7 @@ class Asset(AccountsController):
self.get_gl_dict(
{
"account": fixed_asset_account,
"against_type": "Account",
"against": cwip_account,
"against_link": cwip_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"debit": self.purchase_receipt_amount,
@@ -1004,7 +1008,7 @@ def make_asset_movement(assets, purpose=None):
assets = json.loads(assets)
if len(assets) == 0:
frappe.throw(_("Atleast one asset has to be selected."))
frappe.throw(_("At least one asset has to be selected."))
asset_movement = frappe.new_doc("Asset Movement")
asset_movement.quantity = len(assets)
@@ -1031,6 +1035,8 @@ def is_cwip_accounting_enabled(asset_category):
@frappe.whitelist()
def get_asset_value_after_depreciation(asset_name, finance_book=None):
asset = frappe.get_doc("Asset", asset_name)
if not asset.calculate_depreciation:
return flt(asset.value_after_depreciation)
return asset.get_value_after_depreciation(finance_book)

View File

@@ -19,6 +19,7 @@ from frappe.utils import (
)
from frappe.utils.user import get_users_with_role
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_checks_for_pl_and_bs_accounts,
)
@@ -522,6 +523,13 @@ def depreciate_asset(asset_doc, date, notes):
make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date)
cancel_depreciation_entries(asset_doc, date)
@erpnext.allow_regional
def cancel_depreciation_entries(asset_doc, date):
pass
def reset_depreciation_schedule(asset_doc, date, notes):
if not asset_doc.calculate_depreciation:
@@ -553,6 +561,8 @@ def modify_depreciation_schedule_for_asset_repairs(asset, notes):
def reverse_depreciation_entry_made_after_disposal(asset, date):
for row in asset.get("finance_books"):
asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active", row.finance_book)
if not asset_depr_schedule_doc:
continue
for schedule_idx, schedule in enumerate(asset_depr_schedule_doc.get("depreciation_schedule")):
if schedule.schedule_date == date:

View File

@@ -251,16 +251,7 @@ class TestAsset(AssetSetup):
flt(18000.0 + pro_rata_amount, asset.precision("gross_purchase_amount")),
0.0,
),
(
"_Test Fixed Asset - _TC",
0.0,
flt(18000.0 + pro_rata_amount, asset.precision("gross_purchase_amount")),
),
(
"_Test Fixed Asset - _TC",
0.0,
flt(82000.0 - pro_rata_amount, asset.precision("gross_purchase_amount")),
),
("_Test Fixed Asset - _TC", 0.0, 100000.0),
(
"_Test Gain/Loss on Asset Disposal - _TC",
flt(82000.0 - pro_rata_amount, asset.precision("gross_purchase_amount")),
@@ -900,7 +891,7 @@ class TestDepreciationMethods(AssetSetup):
["2030-12-31", 28630.14, 28630.14],
["2031-12-31", 35684.93, 64315.07],
["2032-12-31", 17842.46, 82157.53],
["2033-06-06", 5342.47, 87500.0],
["2033-06-06", 5342.46, 87499.99],
]
schedules = [
@@ -1012,7 +1003,7 @@ class TestDepreciationBasics(AssetSetup):
asset_depr_schedule_doc = get_asset_depr_schedule_doc(asset.name, "Active")
depreciation_amount = get_depreciation_amount(
asset_depr_schedule_doc, asset, 100000, asset.finance_books[0]
asset_depr_schedule_doc, asset, 100000, 100000, asset.finance_books[0]
)
self.assertEqual(depreciation_amount, 30000)

View File

@@ -21,10 +21,10 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
this.show_stock_ledger();
}
if (this.frm.doc.stock_items && !this.frm.doc.stock_items.length && this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
this.get_target_asset_details();
}
// if (this.frm.doc.stock_items && !this.frm.doc.stock_items.length && this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
// this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
// this.get_target_asset_details();
// }
}
setup_queries() {
@@ -143,13 +143,20 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
},
callback: function (r) {
if (!r.exc && r.message) {
me.frm.clear_table("stock_items");
for (let item of r.message) {
me.frm.add_child("stock_items", item);
if(r.message[0] && r.message[0].length) {
me.frm.clear_table("stock_items");
for (let item of r.message[0]) {
me.frm.add_child("stock_items", item);
}
refresh_field("stock_items");
}
if (r.message[1] && r.message[1].length) {
me.frm.clear_table("asset_items");
for (let item of r.message[1]) {
me.frm.add_child("asset_items", item);
}
me.frm.refresh_field("asset_items");
}
refresh_field("stock_items");
me.calculate_totals();
}

View File

@@ -136,11 +136,20 @@ class AssetCapitalization(StockController):
"Stock Ledger Entry",
"Repost Item Valuation",
"Serial and Batch Bundle",
"Asset",
)
self.cancel_target_asset()
self.update_stock_ledger()
self.make_gl_entries()
self.restore_consumed_asset_items()
def cancel_target_asset(self):
if self.entry_type == "Capitalization" and self.target_asset:
asset_doc = frappe.get_doc("Asset", self.target_asset)
frappe.db.set_value("Asset", self.target_asset, "capitalized_in", None)
if asset_doc.docstatus == 1:
asset_doc.cancel()
def set_title(self):
self.title = self.target_asset_name or self.target_item_name or self.target_item_code
@@ -485,9 +494,7 @@ class AssetCapitalization(StockController):
self.get_gl_dict(
{
"account": account,
"against_type": "Account",
"against": target_account,
"against_link": target_account,
"cost_center": item_row.cost_center,
"project": item_row.get("project") or self.get("project"),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
@@ -528,9 +535,7 @@ class AssetCapitalization(StockController):
self.set_consumed_asset_status(asset)
for gle in fixed_asset_gl_entries:
gle["against_type"] = "Account"
gle["against"] = target_account
gle["against_link"] = target_account
gl_entries.append(self.get_gl_dict(gle, item=item))
target_against.add(gle["account"])
@@ -546,9 +551,7 @@ class AssetCapitalization(StockController):
self.get_gl_dict(
{
"account": item_row.expense_account,
"against_type": "Account",
"against": target_account,
"against_link": target_account,
"cost_center": item_row.cost_center,
"project": item_row.get("project") or self.get("project"),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
@@ -559,46 +562,41 @@ class AssetCapitalization(StockController):
)
def get_gl_entries_for_target_item(self, gl_entries, target_against, precision):
for target_account in target_against:
if self.target_is_fixed_asset:
# Capitalization
if self.target_is_fixed_asset:
# Capitalization
gl_entries.append(
self.get_gl_dict(
{
"account": self.target_fixed_asset_account,
"against": ", ".join(target_against),
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": flt(self.total_value, precision),
"cost_center": self.get("cost_center"),
},
item=self,
)
)
else:
# Target Stock Item
sle_list = self.sle_map.get(self.name)
for sle in sle_list:
stock_value_difference = flt(sle.stock_value_difference, precision)
account = self.warehouse_account[sle.warehouse]["account"]
gl_entries.append(
self.get_gl_dict(
{
"account": self.target_fixed_asset_account,
"against_type": "Account",
"against": target_account,
"against_link": target_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": flt(self.total_value, precision) / len(target_against),
"cost_center": self.get("cost_center"),
"account": account,
"against": ", ".join(target_against),
"cost_center": self.cost_center,
"project": self.get("project"),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
"debit": stock_value_difference,
},
self.warehouse_account[sle.warehouse]["account_currency"],
item=self,
)
)
else:
# Target Stock Item
sle_list = self.sle_map.get(self.name)
for sle in sle_list:
stock_value_difference = flt(sle.stock_value_difference, precision)
account = self.warehouse_account[sle.warehouse]["account"]
gl_entries.append(
self.get_gl_dict(
{
"account": account,
"against_type": "Account",
"against": target_account,
"against_link": target_account,
"cost_center": self.cost_center,
"project": self.get("project"),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
"debit": stock_value_difference / len(target_against),
},
self.warehouse_account[sle.warehouse]["account_currency"],
item=self,
)
)
def create_target_asset(self):
if (
@@ -892,7 +890,6 @@ def get_consumed_asset_details(args):
out.cost_center = get_default_cost_center(
args, item_defaults, item_group_defaults, brand_defaults
)
return out
@@ -940,10 +937,27 @@ def get_items_tagged_to_wip_composite_asset(asset):
"qty",
"valuation_rate",
"amount",
"is_fixed_asset",
"parent",
]
pr_items = frappe.get_all(
"Purchase Receipt Item", filters={"wip_composite_asset": asset}, fields=fields
"Purchase Receipt Item", filters={"wip_composite_asset": asset, "docstatus": 1}, fields=fields
)
return pr_items
stock_items = []
asset_items = []
for d in pr_items:
if not d.is_fixed_asset:
stock_items.append(frappe._dict(d))
else:
asset_details = frappe.db.get_value(
"Asset",
{"item_code": d.item_code, "purchase_receipt": d.parent},
["name as asset", "asset_name"],
as_dict=1,
)
d.update(asset_details)
asset_items.append(frappe._dict(d))
return stock_items, asset_items

View File

@@ -98,12 +98,12 @@ class TestAssetCapitalization(unittest.TestCase):
# Test General Ledger Entries
expected_gle = {
"_Test Fixed Asset - TCP1": 2999.99,
"_Test Fixed Asset - TCP1": 3000,
"Expenses Included In Asset Valuation - TCP1": -1000,
"_Test Warehouse - TCP1": -2000,
"Round Off - TCP1": 0.01,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
self.assertEqual(actual_gle, expected_gle)
# Test Stock Ledger Entries
@@ -189,10 +189,9 @@ class TestAssetCapitalization(unittest.TestCase):
# Test General Ledger Entries
default_expense_account = frappe.db.get_value("Company", company, "default_expense_account")
expected_gle = {
"_Test Fixed Asset - _TC": 2999.99,
"_Test Fixed Asset - _TC": 3000,
"Expenses Included In Asset Valuation - _TC": -1000,
default_expense_account: -2000,
"Round Off - _TC": 0.01,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
@@ -377,10 +376,9 @@ class TestAssetCapitalization(unittest.TestCase):
# Test General Ledger Entries
expected_gle = {
"_Test Warehouse - TCP1": consumed_asset_value_before_disposal,
"_Test Accumulated Depreciations - TCP1": accumulated_depreciation,
"_Test Fixed Asset - TCP1": -consumed_asset_purchase_value,
"_Test Warehouse - TCP1": consumed_asset_value_before_disposal - 0.01,
"Round Off - TCP1": 0.01,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
self.assertEqual(actual_gle, expected_gle)

View File

@@ -7,6 +7,7 @@ from frappe.model.document import Document
from frappe.utils import (
add_days,
add_months,
add_years,
cint,
date_diff,
flt,
@@ -18,6 +19,7 @@ from frappe.utils import (
)
import erpnext
from erpnext.accounts.utils import get_fiscal_year
class AssetDepreciationSchedule(Document):
@@ -283,12 +285,20 @@ class AssetDepreciationSchedule(Document):
depreciation_amount = 0
number_of_pending_depreciations = final_number_of_depreciations - start
yearly_opening_wdv = value_after_depreciation
current_fiscal_year_end_date = None
for n in range(start, final_number_of_depreciations):
# If depreciation is already completed (for double declining balance)
if skip_row:
continue
schedule_date = add_months(row.depreciation_start_date, n * cint(row.frequency_of_depreciation))
if not current_fiscal_year_end_date:
current_fiscal_year_end_date = get_fiscal_year(row.depreciation_start_date)[2]
elif getdate(schedule_date) > getdate(current_fiscal_year_end_date):
current_fiscal_year_end_date = add_years(current_fiscal_year_end_date, 1)
yearly_opening_wdv = value_after_depreciation
if n > 0 and len(self.get("depreciation_schedule")) > n - 1:
prev_depreciation_amount = self.get("depreciation_schedule")[n - 1].depreciation_amount
else:
@@ -298,6 +308,7 @@ class AssetDepreciationSchedule(Document):
self,
asset_doc,
value_after_depreciation,
yearly_opening_wdv,
row,
n,
prev_depreciation_amount,
@@ -341,10 +352,7 @@ class AssetDepreciationSchedule(Document):
n == 0
and (has_pro_rata or has_wdv_or_dd_non_yearly_pro_rata)
and not self.opening_accumulated_depreciation
and get_updated_rate_of_depreciation_for_wdv_and_dd(
asset_doc, value_after_depreciation, row, False
)
== row.rate_of_depreciation
and not self.flags.wdv_it_act_applied
):
from_date = add_days(
asset_doc.available_for_use_date, -1
@@ -404,8 +412,9 @@ class AssetDepreciationSchedule(Document):
if not depreciation_amount:
continue
value_after_depreciation -= flt(
depreciation_amount, asset_doc.precision("gross_purchase_amount")
value_after_depreciation = flt(
value_after_depreciation - flt(depreciation_amount),
asset_doc.precision("gross_purchase_amount"),
)
# Adjust depreciation amount in the last period based on the expected value after useful life
@@ -585,6 +594,7 @@ def get_depreciation_amount(
asset_depr_schedule,
asset,
depreciable_value,
yearly_opening_wdv,
fb_row,
schedule_idx=0,
prev_depreciation_amount=0,
@@ -596,26 +606,18 @@ def get_depreciation_amount(
asset_depr_schedule, asset, fb_row, schedule_idx, number_of_pending_depreciations
)
else:
rate_of_depreciation = get_updated_rate_of_depreciation_for_wdv_and_dd(
asset, depreciable_value, fb_row
)
return get_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
rate_of_depreciation,
fb_row.frequency_of_depreciation,
yearly_opening_wdv,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
)
@erpnext.allow_regional
def get_updated_rate_of_depreciation_for_wdv_and_dd(
asset, depreciable_value, fb_row, show_msg=True
):
return fb_row.rate_of_depreciation
def get_straight_line_or_manual_depr_amount(
asset_depr_schedule, asset, row, schedule_idx, number_of_pending_depreciations
):
@@ -751,30 +753,57 @@ def get_asset_shift_factors_map():
return dict(frappe.db.get_all("Asset Shift Factor", ["shift_name", "shift_factor"], as_list=True))
@erpnext.allow_regional
def get_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
rate_of_depreciation,
frequency_of_depreciation,
yearly_opening_wdv,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
):
if cint(frequency_of_depreciation) == 12:
return flt(depreciable_value) * (flt(rate_of_depreciation) / 100)
return get_default_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
)
def get_default_wdv_or_dd_depr_amount(
asset,
fb_row,
depreciable_value,
schedule_idx,
prev_depreciation_amount,
has_wdv_or_dd_non_yearly_pro_rata,
asset_depr_schedule,
):
if cint(fb_row.frequency_of_depreciation) == 12:
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
else:
if has_wdv_or_dd_non_yearly_pro_rata:
if schedule_idx == 0:
return flt(depreciable_value) * (flt(rate_of_depreciation) / 100)
elif schedule_idx % (12 / cint(frequency_of_depreciation)) == 1:
return flt(depreciable_value) * (flt(fb_row.rate_of_depreciation) / 100)
elif schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 1:
return (
flt(depreciable_value) * flt(frequency_of_depreciation) * (flt(rate_of_depreciation) / 1200)
flt(depreciable_value)
* flt(fb_row.frequency_of_depreciation)
* (flt(fb_row.rate_of_depreciation) / 1200)
)
else:
return prev_depreciation_amount
else:
if schedule_idx % (12 / cint(frequency_of_depreciation)) == 0:
if schedule_idx % (12 / cint(fb_row.frequency_of_depreciation)) == 0:
return (
flt(depreciable_value) * flt(frequency_of_depreciation) * (flt(rate_of_depreciation) / 1200)
flt(depreciable_value)
* flt(fb_row.frequency_of_depreciation)
* (flt(fb_row.rate_of_depreciation) / 1200)
)
else:
return prev_depreciation_amount

View File

@@ -94,7 +94,6 @@
},
{
"default": "0",
"depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"",
"fieldname": "daily_prorata_based",
"fieldtype": "Check",
"label": "Depreciate based on daily pro-rata"
@@ -110,7 +109,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2023-11-29 00:57:07.579777",
"modified": "2023-12-29 08:49:39.876439",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Finance Book",

View File

@@ -40,7 +40,7 @@ class AssetMaintenance(Document):
if getdate(task.next_due_date) < getdate(nowdate()):
task.maintenance_status = "Overdue"
if not task.assign_to and self.docstatus == 0:
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
throw(_("Row #{}: Please assign task to a member.").format(task.idx))
def on_update(self):
for task in self.get("asset_maintenance_tasks"):

View File

@@ -285,9 +285,7 @@ class AssetRepair(AccountsController):
"account": fixed_asset_account,
"debit": self.repair_cost,
"debit_in_account_currency": self.repair_cost,
"against_type": "Account",
"against": pi_expense_account,
"against_link": pi_expense_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
@@ -306,9 +304,7 @@ class AssetRepair(AccountsController):
"account": pi_expense_account,
"credit": self.repair_cost,
"credit_in_account_currency": self.repair_cost,
"against_type": "Account",
"against": fixed_asset_account,
"against_link": fixed_asset_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
@@ -342,9 +338,7 @@ class AssetRepair(AccountsController):
"account": item.expense_account or default_expense_account,
"credit": item.amount,
"credit_in_account_currency": item.amount,
"against_type": "Account",
"against": fixed_asset_account,
"against_link": fixed_asset_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,
@@ -361,9 +355,7 @@ class AssetRepair(AccountsController):
"account": fixed_asset_account,
"debit": item.amount,
"debit_in_account_currency": item.amount,
"against_type": "Account",
"against": item.expense_account or default_expense_account,
"against_link": item.expense_account or default_expense_account,
"voucher_type": self.doctype,
"voucher_no": self.name,
"cost_center": self.cost_center,

View File

@@ -2,14 +2,14 @@
"action": "Show Form Tour",
"action_label": "Let's review existing Asset Category",
"creation": "2021-08-13 14:26:18.656303",
"description": "# Asset Category\n\nAn Asset Category classifies different assets of a Company.\n\nYou can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipments\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n - Depreciation type and duration\n - Fixed asset account\n - Depreciation account\n",
"description": "# Asset Category\n\nAn Asset Category classifies different assets of a Company.\n\nYou can create an Asset Category based on the type of assets. For example, all your desktops and laptops can be part of an Asset Category named \"Electronic Equipment\". Create a separate category for furniture. Also, you can update default properties for each category, like:\n - Depreciation type and duration\n - Fixed asset account\n - Depreciation account\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2021-11-23 10:02:03.242127",
"modified": "2024-01-24 02:20:26.145996",
"modified_by": "Administrator",
"name": "Asset Category",
"owner": "Administrator",

View File

@@ -202,7 +202,7 @@ def prepare_chart_data(data, filters):
"values": [flt(d.get("asset_value"), 2) for d in labels_values_map.values()],
},
{
"name": _("Depreciatied Amount"),
"name": _("Depreciated Amount"),
"values": [flt(d.get("depreciated_amount"), 2) for d in labels_values_map.values()],
},
],

View File

@@ -196,18 +196,18 @@
"type": "Link"
}
],
"modified": "2023-05-24 14:47:20.243146",
"modified": "2024-01-05 17:40:34.570041",
"modified_by": "Administrator",
"module": "Assets",
"name": "Assets",
"number_cards": [],
"owner": "Administrator",
"parent_page": "Accounting",
"parent_page": "",
"public": 1,
"quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 4.0,
"sequence_id": 7.0,
"shortcuts": [
{
"label": "Asset",

View File

@@ -214,7 +214,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-01-05 15:26:02.320942",
"modified": "2024-01-12 16:42:01.894346",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@@ -240,39 +240,24 @@
"write": 1
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts User",
"share": 1
"role": "Accounts User"
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "Accounts Manager",
"share": 1
"role": "Accounts Manager"
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "Stock Manager",
"share": 1
"role": "Stock Manager"
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "Stock User",
"share": 1
"role": "Stock User"
},
{
"email": 1,
"print": 1,
"read": 1,
"role": "Purchase User",
"share": 1
"role": "Purchase User"
}
],
"sort_field": "modified",

View File

@@ -134,6 +134,7 @@
"more_info_tab",
"tracking_section",
"status",
"advance_payment_status",
"column_break_75",
"per_billed",
"per_received",
@@ -1269,13 +1270,25 @@
"fieldtype": "Tab Break",
"label": "Connections",
"show_dashboard": 1
},
{
"fieldname": "advance_payment_status",
"fieldtype": "Select",
"hidden": 1,
"in_standard_filter": 1,
"label": "Advance Payment Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Not Initiated\nInitiated\nPartially Paid\nFully Paid",
"print_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
"modified": "2023-10-01 20:58:07.851037",
"modified": "2023-10-10 13:37:40.158761",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
@@ -1330,4 +1343,4 @@
"timeline_field": "supplier",
"title_field": "supplier_name",
"track_changes": 1
}
}

View File

@@ -215,6 +215,10 @@ class PurchaseOrder(BuyingController):
self.validate_fg_item_for_subcontracting()
self.set_received_qty_for_drop_ship_items()
if not self.advance_payment_status:
self.advance_payment_status = "Not Initiated"
validate_inter_company_party(
self.doctype, self.supplier, self.company, self.inter_company_order_reference
)

View File

@@ -1,6 +1,6 @@
frappe.listview_settings['Purchase Order'] = {
add_fields: ["base_grand_total", "company", "currency", "supplier",
"supplier_name", "per_received", "per_billed", "status"],
"supplier_name", "per_received", "per_billed", "status", "advance_payment_status"],
get_indicator: function (doc) {
if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
@@ -8,6 +8,8 @@ frappe.listview_settings['Purchase Order'] = {
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.status === "Delivered") {
return [__("Delivered"), "green", "status,=,Closed"];
} else if (doc.advance_payment_status == "Initiated") {
return [__("To Pay"), "gray", "advance_payment_status,=,Initiated"];
} else if (flt(doc.per_received, 2) < 100 && doc.status !== "Closed") {
if (flt(doc.per_billed, 2) < 100) {
return [__("To Receive and Bill"), "orange",

View File

@@ -1021,6 +1021,33 @@ class TestPurchaseOrder(FrappeTestCase):
self.assertTrue(frappe.db.get_value("Subcontracting Order", {"purchase_order": po.name}))
def test_purchase_order_advance_payment_status(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
po = create_purchase_order()
self.assertEqual(
frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Not Initiated"
)
pr = make_payment_request(dt=po.doctype, dn=po.name, submit_doc=True, return_doc=True)
self.assertEqual(frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Initiated")
pe = get_payment_entry(po.doctype, po.name).save().submit()
self.assertEqual(
frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Fully Paid"
)
pe.reload()
pe.cancel()
self.assertEqual(frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Initiated")
pr.reload()
pr.cancel()
self.assertEqual(
frappe.db.get_value(po.doctype, po.name, "advance_payment_status"), "Not Initiated"
)
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier

View File

@@ -54,7 +54,7 @@ frappe.query_reports["Purchase Order Analysis"] = {
"fieldtype": "MultiSelectList",
"width": "80",
get_data: function(txt) {
let status = ["To Bill", "To Receive", "To Receive and Bill", "Completed"]
let status = ["To Pay", "To Bill", "To Receive", "To Receive and Bill", "Completed"]
let options = []
for (let option of status){
options.push({

View File

@@ -7,6 +7,7 @@ import json
import frappe
from frappe import _, bold, qb, throw
from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied
from frappe.query_builder import Criterion
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import Abs, Sum
from frappe.utils import (
@@ -21,12 +22,14 @@ from frappe.utils import (
get_link_to_form,
getdate,
nowdate,
parse_json,
today,
)
import erpnext
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_accounting_dimensions,
get_dimensions,
)
from erpnext.accounts.doctype.pricing_rule.utils import (
apply_pricing_rule_for_free_items,
@@ -831,6 +834,37 @@ class AccountsController(TransactionBase):
self.extend("taxes", get_taxes_and_charges(tax_master_doctype, self.get("taxes_and_charges")))
def append_taxes_from_item_tax_template(self):
if not frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template"):
return
for row in self.items:
item_tax_rate = row.get("item_tax_rate")
if not item_tax_rate:
continue
if isinstance(item_tax_rate, str):
item_tax_rate = parse_json(item_tax_rate)
for account_head, rate in item_tax_rate.items():
row = self.get_tax_row(account_head)
if not row:
self.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": account_head,
"rate": 0,
"description": account_head,
},
)
def get_tax_row(self, account_head):
for row in self.taxes:
if row.account_head == account_head:
return row
def set_other_charges(self):
self.set("taxes", [])
self.set_taxes()
@@ -930,7 +964,7 @@ class AccountsController(TransactionBase):
# Update details in transaction currency
gl_dict.update(
{
"transaction_currency": args.get("currency") or self.get("currency") or self.company_currency,
"transaction_currency": self.get("currency") or self.company_currency,
"transaction_exchange_rate": self.get("conversion_rate", 1),
"debit_in_transaction_currency": self.get_value_in_transaction_currency(
account_currency, args, "debit"
@@ -969,10 +1003,10 @@ class AccountsController(TransactionBase):
return self.doctype
def get_value_in_transaction_currency(self, account_currency, args, field):
if account_currency == args.get("currency") or self.get("currency"):
if account_currency == self.get("currency"):
return args.get(field + "_in_account_currency")
else:
return flt(args.get(field, 0) / (args.get("conversion_rate") or self.get("conversion_rate", 1)))
return flt(args.get(field, 0) / self.get("conversion_rate", 1))
def validate_qty_is_not_zero(self):
for item in self.items:
@@ -1161,7 +1195,6 @@ class AccountsController(TransactionBase):
)
credit_or_debit = "credit" if self.doctype == "Purchase Invoice" else "debit"
against_type = "Supplier" if self.doctype == "Purchase Invoice" else "Customer"
against = self.supplier if self.doctype == "Purchase Invoice" else self.customer
if precision_loss:
@@ -1169,9 +1202,7 @@ class AccountsController(TransactionBase):
self.get_gl_dict(
{
"account": round_off_account,
"against_type": against_type,
"against": against,
"against_link": against,
credit_or_debit: precision_loss,
"cost_center": round_off_cost_center
if self.use_company_roundoff_cost_center
@@ -1219,7 +1250,9 @@ class AccountsController(TransactionBase):
return True
return False
def make_exchange_gain_loss_journal(self, args: dict = None) -> None:
def make_exchange_gain_loss_journal(
self, args: dict = None, dimensions_dict: dict = None
) -> None:
"""
Make Exchange Gain/Loss journal for Invoices and Payments
"""
@@ -1274,6 +1307,7 @@ class AccountsController(TransactionBase):
self.name,
arg.get("referenced_row"),
arg.get("cost_center"),
dimensions_dict,
)
frappe.msgprint(
_("Exchange Gain/Loss amount has been booked through {0}").format(
@@ -1354,6 +1388,7 @@ class AccountsController(TransactionBase):
self.name,
d.idx,
self.cost_center,
dimensions_dict,
)
frappe.msgprint(
_("Exchange Gain/Loss amount has been booked through {0}").format(
@@ -1418,14 +1453,25 @@ class AccountsController(TransactionBase):
if lst:
from erpnext.accounts.utils import reconcile_against_document
reconcile_against_document(lst)
# pass dimension values to utility method
active_dimensions = get_dimensions()[0]
for x in lst:
for dim in active_dimensions:
if self.get(dim.fieldname):
x.update({dim.fieldname: self.get(dim.fieldname)})
reconcile_against_document(lst, active_dimensions=active_dimensions)
def on_cancel(self):
from erpnext.accounts.doctype.bank_transaction.bank_transaction import (
remove_from_bank_transaction,
)
from erpnext.accounts.utils import (
cancel_exchange_gain_loss_journal,
unlink_ref_doc_from_payment_entries,
)
remove_from_bank_transaction(self.doctype, self.name)
if self.doctype in ["Sales Invoice", "Purchase Invoice", "Payment Entry", "Journal Entry"]:
# Cancel Exchange Gain/Loss Journal before unlinking
cancel_exchange_gain_loss_journal(self)
@@ -1520,13 +1566,11 @@ class AccountsController(TransactionBase):
if self.doctype == "Purchase Invoice":
dr_or_cr = "credit"
rev_dr_cr = "debit"
against_type = "Supplier"
supplier_or_customer = self.supplier
else:
dr_or_cr = "debit"
rev_dr_cr = "credit"
against_type = "Customer"
supplier_or_customer = self.customer
if enable_discount_accounting:
@@ -1551,9 +1595,7 @@ class AccountsController(TransactionBase):
self.get_gl_dict(
{
"account": item.discount_account,
"against_type": against_type,
"against": supplier_or_customer,
"against_link": supplier_or_customer,
dr_or_cr: flt(
discount_amount * self.get("conversion_rate"), item.precision("discount_amount")
),
@@ -1571,9 +1613,7 @@ class AccountsController(TransactionBase):
self.get_gl_dict(
{
"account": income_or_expense_account,
"against_type": against_type,
"against": supplier_or_customer,
"against_link": supplier_or_customer,
rev_dr_cr: flt(
discount_amount * self.get("conversion_rate"), item.precision("discount_amount")
),
@@ -1596,9 +1636,7 @@ class AccountsController(TransactionBase):
self.get_gl_dict(
{
"account": self.additional_discount_account,
"against_type": against_type,
"against": supplier_or_customer,
"against_link": supplier_or_customer,
dr_or_cr: self.base_discount_amount,
"cost_center": self.cost_center or erpnext.get_default_cost_center(self.company),
},
@@ -1755,7 +1793,10 @@ class AccountsController(TransactionBase):
def set_total_advance_paid(self):
ple = frappe.qb.DocType("Payment Ledger Entry")
party = self.customer if self.doctype == "Sales Order" else self.supplier
if self.doctype in frappe.get_hooks("advance_payment_customer_doctypes"):
party = self.customer
if self.doctype in frappe.get_hooks("advance_payment_supplier_doctypes"):
party = self.supplier
advance = (
frappe.qb.from_(ple)
.select(ple.account_currency, Abs(Sum(ple.amount_in_account_currency)).as_("amount"))
@@ -1769,6 +1810,8 @@ class AccountsController(TransactionBase):
.run(as_dict=True)
)
advance_paid, order_total = None, None
if advance:
advance = advance[0]
@@ -1797,7 +1840,38 @@ class AccountsController(TransactionBase):
).format(formatted_advance_paid, self.name, formatted_order_total)
)
frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid)
self.db_set("advance_paid", advance_paid)
self.set_advance_payment_status(advance_paid, order_total)
def set_advance_payment_status(
self, advance_paid: float | None = None, order_total: float | None = None
):
new_status = None
# if money is paid set the paid states
if advance_paid:
new_status = "Partially Paid" if advance_paid < order_total else "Fully Paid"
if not new_status:
prs = frappe.db.count(
"Payment Request",
{
"reference_doctype": self.doctype,
"reference_name": self.name,
"docstatus": 1,
},
)
if self.doctype in frappe.get_hooks("advance_payment_customer_doctypes"):
new_status = "Requested" if prs else "Not Requested"
if self.doctype in frappe.get_hooks("advance_payment_supplier_doctypes"):
new_status = "Initiated" if prs else "Not Initiated"
if new_status == self.advance_payment_status:
return
self.db_set("advance_payment_status", new_status)
self.set_status(update=True)
self.notify_update()
@property
def company_abbr(self):
@@ -1962,7 +2036,7 @@ class AccountsController(TransactionBase):
self.remove(item)
def set_payment_schedule(self):
if self.doctype == "Sales Invoice" and self.is_pos:
if (self.doctype == "Sales Invoice" and self.is_pos) or self.get("is_opening") == "Yes":
self.payment_terms_template = ""
return
@@ -2145,7 +2219,7 @@ class AccountsController(TransactionBase):
)
def validate_payment_schedule_amount(self):
if self.doctype == "Sales Invoice" and self.is_pos:
if (self.doctype == "Sales Invoice" and self.is_pos) or self.get("is_opening") == "Yes":
return
party_account_currency = self.get("party_account_currency")
@@ -2690,47 +2764,37 @@ def get_common_query(
q = q.select((payment_entry.target_exchange_rate).as_("exchange_rate"))
if condition:
if condition.get("name", None):
q = q.where(payment_entry.name.like(f"%{condition.get('name')}%"))
# conditions should be built as an array and passed as Criterion
common_filter_conditions = []
common_filter_conditions.append(payment_entry.company == condition["company"])
if condition.get("name", None):
common_filter_conditions.append(payment_entry.name.like(f"%{condition.get('name')}%"))
if condition.get("from_payment_date"):
common_filter_conditions.append(payment_entry.posting_date.gte(condition["from_payment_date"]))
if condition.get("to_payment_date"):
common_filter_conditions.append(payment_entry.posting_date.lte(condition["to_payment_date"]))
q = q.where(payment_entry.company == condition["company"])
q = (
q.where(payment_entry.posting_date >= condition["from_payment_date"])
if condition.get("from_payment_date")
else q
)
q = (
q.where(payment_entry.posting_date <= condition["to_payment_date"])
if condition.get("to_payment_date")
else q
)
if condition.get("get_payments") == True:
q = (
q.where(payment_entry.cost_center == condition["cost_center"])
if condition.get("cost_center")
else q
)
q = (
q.where(payment_entry.unallocated_amount >= condition["minimum_payment_amount"])
if condition.get("minimum_payment_amount")
else q
)
q = (
q.where(payment_entry.unallocated_amount <= condition["maximum_payment_amount"])
if condition.get("maximum_payment_amount")
else q
)
else:
q = (
q.where(payment_entry.total_debit >= condition["minimum_payment_amount"])
if condition.get("minimum_payment_amount")
else q
)
q = (
q.where(payment_entry.total_debit <= condition["maximum_payment_amount"])
if condition.get("maximum_payment_amount")
else q
)
if condition.get("cost_center"):
common_filter_conditions.append(payment_entry.cost_center == condition["cost_center"])
if condition.get("accounting_dimensions"):
for field, val in condition.get("accounting_dimensions").items():
common_filter_conditions.append(payment_entry[field] == val)
if condition.get("minimum_payment_amount"):
common_filter_conditions.append(
payment_entry.unallocated_amount.gte(condition["minimum_payment_amount"])
)
if condition.get("maximum_payment_amount"):
common_filter_conditions.append(
payment_entry.unallocated_amount.lte(condition["maximum_payment_amount"])
)
q = q.where(Criterion.all(common_filter_conditions))
q = q.orderby(payment_entry.posting_date)
q = q.limit(limit) if limit else q

View File

@@ -744,11 +744,8 @@ class BuyingController(SubcontractingController):
item_data = frappe.db.get_value(
"Item", row.item_code, ["asset_naming_series", "asset_category"], as_dict=1
)
if is_grouped_asset:
purchase_amount = flt(row.base_amount + row.item_tax_amount)
else:
purchase_amount = flt(row.base_rate + row.item_tax_amount)
asset_quantity = row.qty if is_grouped_asset else 1
purchase_amount = flt(row.valuation_rate) * asset_quantity
asset = frappe.get_doc(
{
@@ -764,7 +761,7 @@ class BuyingController(SubcontractingController):
"calculate_depreciation": 0,
"purchase_receipt_amount": purchase_amount,
"gross_purchase_amount": purchase_amount,
"asset_quantity": row.qty if is_grouped_asset else 1,
"asset_quantity": asset_quantity,
"purchase_receipt": self.name if self.doctype == "Purchase Receipt" else None,
"purchase_invoice": self.name if self.doctype == "Purchase Invoice" else None,
}

View File

@@ -56,7 +56,11 @@ def make_variant_based_on_manufacturer(template, manufacturer, manufacturer_part
copy_attributes_to_variant(template, variant)
variant.item_code = append_number_if_name_exists("Item", template.name)
variant_name = f"{template.name} - {manufacturer}"
if manufacturer_part_no:
variant_name += f" - {manufacturer_part_no}"
variant.item_code = append_number_if_name_exists("Item", variant_name)
variant.flags.ignore_mandatory = True
variant.save()

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