Compare commits

..

169 Commits

Author SHA1 Message Date
Sahil Khan
4206b52bdc Merge branch 'v11-pre-release' into version-11 2020-02-20 18:03:05 +05:30
Sahil Khan
9e66c86d6f bumped to version 11.1.73 2020-02-20 18:23:05 +05:50
Sahil Khan
ec46b4d4c6 Merge branch 'version-11-hotfix' of https://github.com/frappe/erpnext into v11-pre-release 2020-02-20 18:00:23 +05:30
Mathieu Brunot
39c71e26b9 chore(ci-coverage): Pin coverage 4.5.4 #20646 (#20649)
* chore(ci-coverage): Pin coveralls 4.5.4 #20646

Signed-off-by: mathieu.brunot <mathieu.brunot@monogramm.io>

* chore: Fix coverage

Signed-off-by: mathieu.brunot <mathieu.brunot@monogramm.io>
2020-02-20 12:51:32 +05:30
Deepesh Garg
77285317c0 Merge pull request #20665 from marination/stock-settings-query-v11-hotfix
fix: Set Query on warehouse fields in Stock Settings
2020-02-19 18:59:37 +05:30
marination
a95c09bef6 fix: Server side validation for Warehouses 2020-02-19 11:30:47 +05:30
marination
6b901d0c1a fix: Set Query on warehouse fields in Stock Settings 2020-02-18 21:51:00 +05:30
rohitwaghchaure
8a7ccd9874 Merge pull request #20656 from marination/precision-mr-item-v11-hotfix
fix: Stock Quantity not calculated on client side in Material Request Items.
2020-02-18 12:34:45 +05:30
marination
2f2e748b7a fix: Stock Quantity not calculated on client side in Material Request Items. 2020-02-18 11:19:37 +05:30
Deepesh Garg
549ab68eb0 Merge pull request #20503 from sunhoww/patch-4
fix: [v11] negative stock error at landed cost voucher
2020-02-02 17:35:54 +05:30
Sun Howwrongbum
0b9bf4d0ac fix: negative stock error at landed cost voucher 2020-02-02 16:45:57 +05:30
Nabin Hait
1c5df5dede cannot close task if dependent task are not closed / cancelled (#20433) 2020-01-28 14:08:31 +05:30
Deepesh Garg
41d2357dc4 Merge pull request #20442 from fproldan/fix_sqlinjection_hotfix_v11
fix: SQL Injection in get_product_list_for_group method
2020-01-28 09:17:39 +05:30
NahuelOperto
af79714f40 Fix sql injection 2020-01-27 08:55:35 -03:00
Marica
8a5f31da34 fix: Applied query on PO Supplier popup field in Material Request. (#20233) 2020-01-15 19:24:39 +05:30
Sahil Khan
47a7e3422b Merge branch 'v11-pre-release' into version-11 2020-01-14 14:19:35 +05:30
Sahil Khan
9efb087e22 bumped to version 11.1.72 2020-01-14 14:39:35 +05:50
Sahil Khan
3d58dd6aa5 Merge branch 'v11-pre-release' of https://github.com/frappe/erpnext into v11-pre-release 2020-01-14 12:49:02 +05:30
Sahil Khan
ac7966cd7e bumped to version 11.1.71 2020-01-14 12:47:21 +05:30
sahil28297
61ddb508d4 fix(init): bump version to 11.1.70 2020-01-14 12:47:21 +05:30
Marica
d973fb8823 fix: Added description and title to supplier selection popup in Material Request (#20181)
* fix: Added description and title to supplier selection popup in Material Request

* Update material_request.js

cleanup

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2020-01-07 13:04:56 +05:30
Marica
a649414419 fix: Remove unnecessary Duplicate Entry Error (#20122) 2019-12-27 16:53:00 +05:30
rohitwaghchaure
270f23b966 Merge pull request #20080 from nabinhait/rounding-adjustment
fix: rounding adjustment while both inclusive tax and discount amount present
2019-12-27 11:52:24 +05:30
Nabin Hait
4d745a39e0 fix: rounding adjustment while both inclusive tax and discount amount present 2019-12-25 13:59:24 +05:30
Don-Leopardo
5e0b5cb283 perf: Asset Depreciations and Balances report (#18455) 2019-12-24 17:35:57 +05:30
Sun Howwrongbum
69358cfd40 feat: consider expiry_date during Batch queries (#19972) 2019-12-24 12:30:20 +05:30
RJPvT
ad1ba2bb76 fix: sc object not loaded (#19892)
fix for object not loaded and errors in auto-generate :

Traceback (most recent call last):
  File "/home/frappe/frappe-bench/apps/frappe/frappe/utils/background_jobs.py", line 103, in execute_job
    method(**kwargs)
  File "/home/frappe/frappe-bench/apps/erpnext/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py", line 141, in refresh_scorecards
    sc.save()
TypeError: 'NoneType' object is not callable
2019-12-24 12:20:41 +05:30
DeeMysterio
c44abd2f78 fix(employee onboarding): stop showing irrelevant job offer links for a job applicant (#20055) 2019-12-23 19:02:59 +05:30
Deepesh Garg
0bcada8f3c Merge pull request #20016 from marination/valuation_rate_company_v11_hotfix
fix: Company None not found in get_valuation_rate
2019-12-20 11:56:24 +05:30
marination
a6b110a7d3 fix: Company None not found in get_valuation_rate 2019-12-19 14:50:17 +05:30
Sahil Khan
b4ce43306b Merge branch 'v11-pre-release' into version-11 2019-12-18 13:59:59 +05:30
Sahil Khan
85a9f55fa7 bumped to version 11.1.71 2019-12-18 14:19:59 +05:50
Suraj Shetty
596c0d2060 fix(init): bump version to 11.1.70 (#19986)
fix(init): bump version to 11.1.70
2019-12-18 13:58:01 +05:30
sahil28297
723421f375 fix(init): bump version to 11.1.70 2019-12-18 13:56:34 +05:30
Deepesh Garg
f9297416f2 fix: Append expense account only if expense account exists (#19882) 2019-12-10 12:14:58 +05:30
Nabin Hait
a8d2916e61 Merge branch 'version-11' into version-11-hotfix 2019-12-09 18:08:05 +05:30
Deepesh Garg
0f70f20ec5 Merge pull request #19866 from nextchamp-saqib/ux-fix
fix: tax templates from all companies fetching in receipt
2019-12-09 17:59:44 +05:30
thefalconx33
73d9d8fec9 fix: tax templates from all companies fetching in receipt 2019-12-09 13:59:50 +05:30
Deepesh Garg
c4756e938f fix: Rounding Adjustment GL entry fix (#19840)
* fix: Rounding Adjustment GL entry fix

* fix: Spacing in tab

* fix: Comment fix
2019-12-09 13:03:18 +05:30
Deepesh Garg
faa5d90f1b fix: NoneType' object has no attribute '__getitem__' (#19861) 2019-12-09 11:28:38 +05:30
rohitwaghchaure
3b37a109c5 Merge pull request #19852 from rohitwaghchaure/fixed_timesheet_overlap_issue_v11_hotfix
fix: timesheet overlap error
2019-12-07 14:10:35 +05:30
Rohit Waghchaure
ab4aa53f52 fix: timesheet overlap error 2019-12-07 13:28:09 +05:30
Nabin Hait
3483426fe7 optimize: Optimization of Receivable report filtered based on sales person (#19795) 2019-12-04 15:30:48 +05:30
Deepesh Garg
3039094737 fix: Party name field in trial balacne for party report (#19791) 2019-12-03 16:30:16 +05:30
Nabin Hait
e21602d432 Update accounts_receivable_summary.py 2019-12-03 16:22:22 +05:30
Marica
6067ef3c49 fix: Item qty cannot be zero in Purchase Receipt (#19781) 2019-12-03 12:45:28 +05:30
Deepesh Garg
b78128a7fe Merge pull request #19767 from deepeshgarg007/avaiable_stock_for_v11
fix: Available stock for packing item report
2019-12-02 11:57:07 +05:30
deepeshgarg007
c8cbb87168 fix: Available stock for packing item report 2019-12-01 22:17:46 +05:30
Deepesh Garg
aed8aeb83a fix: Account type in Handling Difference in Inventory account (#19675)
* fix: Account type in Handling Difference in Inventory account

* fix: Add Stock Adjustment account

* fix: Rename account to stock adjustment
2019-11-28 18:29:26 +05:30
Saqib
fa47445e11 fix: due date before posting date for items added to cart yesterday (#19680) 2019-11-28 18:27:55 +05:30
Marica
0220acf100 fix: Changed type of column 'serial_no' in Stock Ledger Entry (#19705) 2019-11-28 18:20:57 +05:30
Marica
0fe8f8e6d9 fix: get_batch_qty_and_serial_no() requires argument 'stock_qty' (#19699) 2019-11-27 15:51:12 +05:30
rohitwaghchaure
f87b766a26 Merge pull request #19688 from deepeshgarg007/sales_invoice_serial_no
fix: Serial no validation against sales invoice
2019-11-27 11:59:46 +05:30
deepeshgarg007
2262e5d443 fix: Validation msg 2019-11-26 16:15:05 +05:30
deepeshgarg007
b9cad8d891 fix: Serial no validation against sales invoice 2019-11-26 15:27:54 +05:30
Marica
dafdc6035a fix: Validation Error message on Prepared Report. (#19640)
Give the user the reason why he has to use filters.
2019-11-22 14:38:53 +05:30
Marica
c8369c10ff fix: Get Current Stock button in Purhase Receipt not working (#19653)
- Current Stock visible in grid view within Supplied Items table of Purchase Receipt
2019-11-22 13:33:11 +05:30
Deepesh Garg
08b8ed5ca6 Merge pull request #19635 from ruchamahabal/fix_cash_entry_v11
fix(minor): default Cash Entry account not getting fetched in Journal Entry (v11)
2019-11-20 22:02:48 +05:30
Rucha Mahabal
6cefdb40d1 fix(Journal Entry): default Cash Entry account not getting fetched 2019-11-20 20:13:04 +05:30
Rohit Waghchaure
3ad65ec57d fix: code cleanup 2019-11-20 13:24:53 +05:30
rohitwaghchaure
364332bcfe Update queries.py 2019-11-20 13:24:44 +05:30
Rohit Waghchaure
9965f443ee fix: not able to select item in sales order 2019-11-20 13:24:34 +05:30
rohitwaghchaure
d87d644dc2 Merge pull request #19621 from rohitwaghchaure/not_able_to_select_item_in_the_sales_order_hotfix
fix: not able to select item in sales order
2019-11-19 19:40:29 +05:30
rohitwaghchaure
eeab3128aa Merge pull request #19623 from rohitwaghchaure/code_cleanup_sales_invoice_credit_note_hotfix
fix: code cleanup
2019-11-19 19:39:36 +05:30
Rohit Waghchaure
7b2cec8da2 fix: code cleanup 2019-11-19 19:27:31 +05:30
rohitwaghchaure
6e3cbd8698 Update queries.py 2019-11-19 19:26:31 +05:30
Rohit Waghchaure
b5e1f846ce fix: not able to select item in sales order 2019-11-19 19:08:44 +05:30
Sahil Khan
f06b31aab4 Merge branch 'v11-pre-release' into version-11 2019-11-18 18:09:02 +05:30
Sahil Khan
f8502317a9 bumped to version 11.1.68 2019-11-18 18:29:02 +05:50
rohitwaghchaure
9c7a33405d Merge pull request #19024 from Alchez/v11-work-order-bugs
fix: Work Order operating cost re-calculation on client-side (v11)
2019-11-15 11:18:39 +05:30
Nabin Hait
0ee46a624c Merge branch 'version-11-hotfix' into v11-pre-release 2019-11-14 18:05:47 +05:30
Nabin Hait
5485d4c435 fix: One serial no can be tagged in multiple invoices if used against different items (#19581) 2019-11-14 13:28:29 +05:30
RJPvT
fb2d4884b3 fix: allow pending within review date (#19577)
* fix: allow pending within review date

referenced - fix: allow Pending on review date #19497
explanation for closing not valid

* fix: codacy
2019-11-14 10:10:02 +05:30
Nabin Hait
3b38a9e418 Accounts Receivable report fixes (#19575)
* fix: Set due date in accounts receivable based on payment terms

* fix: Show AR summary based on outstanding
2019-11-13 18:49:45 +05:30
Deepesh Garg
437d3e37d6 Merge pull request #19566 from deepeshgarg007/balance_sheet_filter
fix: Accumulated Values filter disappearing
2019-11-13 17:47:05 +05:30
Rohan
1b9a55e766 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-11-13 13:08:59 +05:30
deepeshgarg007
a5353a8d04 fix: Accumulated Values filter disappearing 2019-11-13 12:46:19 +05:30
RJPvT
e1bc0a1028 fix: user with invoice role not able to submit (#19555)
fix for a user not having timesheet submit privelige (e.g. a shared timesheet from another department) not being able to submit because of linked fields
2019-11-13 10:47:40 +05:30
Deepesh Garg
92116abd92 Merge pull request #19548 from DeeMysterio/v11-emp-err
fix(employee): show only active employees in the error while marking …
2019-11-11 21:47:58 +05:30
Diksha
e5731b3d0f fix(employee): show only active employees in the error while marking reporting to employee as left 2019-11-11 19:08:48 +05:30
rohitwaghchaure
a36c4326c3 Merge pull request #19449 from surajshetty3416/account-head-fix
fix: not able to change the account type in parent company account head
2019-11-11 15:13:07 +05:30
sahil28297
5a0a4bdcff fix(cart): return rule instead of rule_label_map (#19521)
* fix(cart): return rule instead of rule_label_map

* fix(cart): remove get_value for rule_label_map as well
2019-11-11 11:15:29 +05:30
Nabin Hait
d2dc889849 fix(trial balance): Show opening and closing of group account in single column (#19511) 2019-11-11 10:59:30 +05:30
rohitwaghchaure
dbcdf7e225 minor: added description, uom fields in material request plan item table (#19464)
* fix: added description, uom fields in material request plan item table

* Update material_request_plan_item.json

* Update production_plan.js
2019-11-11 10:57:04 +05:30
rohitwaghchaure
7fdef64152 fix: incorrect balance qty in stock ledger if batch filter set (#19480) 2019-11-08 14:50:12 +05:30
Deepesh Garg
b2be301988 Merge pull request #19529 from deepeshgarg007/gst_check_digit_msg_v11
fix: GSTIN validation msg fix
2019-11-07 23:05:07 +05:30
deepeshgarg007
68db5a6792 fix: GSTIN validation msg fix 2019-11-07 21:58:56 +05:30
Marica
f232965392 fix[minor]: Payment Entry status patch (#19520) 2019-11-07 18:04:16 +05:30
Marica
2ff7197752 fix: Added 'status' field in Payment Entry (#19513) 2019-11-06 19:16:11 +05:30
Anurag Mishra
1d3b5b0437 fix: packed items child table reset on amending docs (#19158) 2019-11-06 16:56:14 +05:30
Nabin Hait
8280d32967 fix: incorrect number of entries while making deferred revenue entry (#19512) 2019-11-06 15:33:36 +05:30
Rohan
4a79072c71 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-11-06 11:39:11 +05:30
Deepesh Garg
721a00cd22 Merge pull request #19489 from DeeMysterio/v11-delivery-dn
fix(sales order): rename delivery to delivery note on sales order mak…
2019-11-04 13:16:50 +05:30
Diksha
8ce7893bf0 fix(sales order): rename delivery to delivery note on sales order make button 2019-11-04 12:19:23 +05:30
Deepesh Garg
0f87282aef Merge pull request #19482 from MaxMorais/patch-9
fix: Wrong datafield type in Task
2019-11-03 17:12:15 +05:30
Deepesh Garg
de51217a80 Merge pull request #19485 from gavindsouza/sales-register-tax-v11
fix: calculate total tax in sales register report
2019-11-03 17:09:30 +05:30
Gavin D'souza
bc01dafbba fix: calculate total tax in sales register report 2019-11-03 14:02:52 +05:30
Maxwell Morais
a985bfc29a Wrong datafield type in Task
The field `depends_on_tasks` is set as `Data`, but it stores a list of strings joined by comma, so with more than 5 tasks, we reach the field size limit of 144 chars and data get trunked, what make us lose data!
2019-11-01 18:31:56 -03:00
Deepesh Garg
08dbb13451 Merge pull request #19424 from marination/search_field
fix: Search field entries included in Item Link field query
2019-11-01 15:40:14 +05:30
rohitwaghchaure
170dd37b86 fix: purchase order issue, margin_rate_or_amount not there in the purchase documents (#19465) 2019-10-31 15:56:05 +05:30
gavin
b1744972e0 Merge pull request #19451 from gavindsouza/hooks-update-v11
chore: moves email digest to long job from regular
2019-10-31 14:34:58 +05:30
marination
7aa993b14b fix: Fetching catched meta and removed description fetch from Search Fields
Description is conditionally fetched and also used in WHERE clause, that is maintained.
Improved naming
2019-10-30 18:39:35 +05:30
gavin
ad89cb0ef3 Merge branch 'version-11-hotfix' into hooks-update-v11 2019-10-30 17:52:26 +05:30
rohitwaghchaure
a185b51f0d Merge pull request #19447 from rohitwaghchaure/not_able_to_select_project_in_work_order_v11
fix: not able to select the project in the work order
2019-10-30 16:32:48 +05:30
gavin
1ff81bca7d Merge branch 'version-11-hotfix' into hooks-update-v11 2019-10-30 15:47:52 +05:30
Gavin D'souza
b02db3c3e8 chore: moves email digest to long job from regular 2019-10-30 15:20:43 +05:30
Suraj Shetty
d1d835347e fix: Pass parent_acc_name 2019-10-30 14:45:11 +05:30
Rohit Waghchaure
ba245553f0 fix: not able to change the account type in parent company account head 2019-10-30 14:39:03 +05:30
Rohit Waghchaure
112902a9c4 fix: not able to select the project in the work order 2019-10-30 14:27:18 +05:30
Anurag Mishra
3f4cdcc7a4 fix: On Specific case if no item code in name (#19420) 2019-10-30 14:18:20 +05:30
rohitwaghchaure
91f81b07d9 fix: not able to select the zero qty batch while making the sales return entry (#19436) 2019-10-30 13:30:28 +05:30
Deepesh Garg
66e92041b9 Merge pull request #19403 from Mangesh-Khairnar/fix-dn-status-11
fix: sync delivery note status in both list view and form view
2019-10-29 14:18:23 +05:30
Rohan
f2dc89c7a0 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-10-29 11:25:40 +05:30
marination
10b226af10 fix: Search field entries included in Item Link field query 2019-10-28 16:18:47 +05:30
Deepesh Garg
115887a886 fix: Better validation msg for difference account in Stock Entry (#19401)
* fix: Better validation msg for difference account

* fix: Make primary info bold
2019-10-28 12:07:57 +05:30
Suraj Shetty
a1f5c22da7 fix: Overwrite default cost center if item has default cost center set. (#19406) 2019-10-28 12:03:58 +05:30
Deepesh Garg
712c01d5bd Merge pull request #19394 from 0Pranav/patch-3
fix: setting incorrect field for party bank account
2019-10-25 12:25:33 +05:30
Mangesh-Khairnar
bd4e296336 fix: sync delivery note status in both list view and form view 2019-10-24 16:20:10 +05:30
Pranav Nachnekar
b52d81ef6a fix: setting incorrect field for party bank account 2019-10-23 15:50:00 +00:00
Shivam Mishra
15432c76a4 fix: icon for opportunity (#19381) 2019-10-23 11:07:33 +05:30
Rohan
dd3cd6e2ba Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-10-22 17:11:39 +05:30
Sahil Khan
5889a29656 Merge branch 'v11-pre-release' into version-11 2019-10-22 17:03:12 +05:30
Sahil Khan
0e7ca6ada7 bumped to version 11.1.67 2019-10-22 17:23:12 +05:50
Anurag Mishra
5a2ea528e8 fix: if naming if item-code and index both are same (#19372) 2019-10-22 11:46:42 +05:30
Saurabh
8957093439 fix: Don't show make jv button if equity or liability account and asset account not specified (#19349) 2019-10-21 16:02:47 +05:30
Nabin Hait
507c435dee Reorder level report fix v11 (#19367)
* fix: Fixed consumed qty based on Stock Ledger Entry

* Update itemwise_recommended_reorder_level.py
2019-10-21 16:01:51 +05:30
Deepesh Garg
8889edad72 Merge pull request #19365 from deepeshgarg007/sales_return_print_fix
fix: Positive qty in sales return print
2019-10-21 15:23:34 +05:30
Nabin Hait
e27d1aebd5 fix: Positive qty in sales return print 2019-10-21 14:28:33 +05:30
Deepesh Garg
ef567eac37 fix: Item Price changes are not persistent after updating cost on submitted BOM (#19357) 2019-10-21 13:27:34 +05:30
rohitwaghchaure
f8e0a2204e Merge pull request #19331 from rohitwaghchaure/minor_loan_not_able_to_make_jv
fix: not able to save journal entry for disbursement amount
2019-10-16 19:02:09 +05:30
Rohit Waghchaure
baecc7fd31 fix: not able to save journal entry for disbursement amount 2019-10-16 18:40:27 +05:30
Rohan
529b465337 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-10-16 15:11:45 +05:30
Deepesh Garg
675e2670b2 fix: Show Create Loan button only if loan is not created (#19291) 2019-10-14 15:50:19 +05:30
Deepesh Garg
3919fd10ad Merge pull request #19289 from deepeshgarg007/chart_fix_analytics_v11
fix: Chart fix in Analytics report when based on item
2019-10-13 09:33:16 +05:30
deepeshgarg007
b4e61e19bb fix: Chart fix in Analytics report 2019-10-12 23:11:28 +05:30
Rohan
85be3ec796 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-10-11 12:50:28 +05:30
Marica
aa3d6ed11e fix: Margin and Discount percentage set correctly via 'Update Items' (#19173) 2019-10-11 11:52:29 +05:30
Nabin Hait
382735ad2f fix: Set incoming rate for standalone sales return (#19264) 2019-10-10 16:40:10 +05:30
Deepesh Garg
8d42b75e29 Merge pull request #19254 from Thunderbottom/e-invoice-disc-fix-v11
chore: check if discount_percentage exists
2019-10-06 23:47:18 +05:30
Chinmay D. Pai
7e03e046ec chore: check if discount_percentage exists
fixes TypeError: '>' not supported between instances of 'NoneType' and 'float'

Signed-off-by: Chinmay D. Pai <chinmaydpai@gmail.com>
2019-10-05 10:20:19 +05:30
Sahil Khan
bfddc8aba1 Merge branch 'version-11-hotfix' into version-11 2019-10-04 13:43:32 +05:30
Sahil Khan
d0dafcc46f bumped to version 11.1.66 2019-10-04 14:03:32 +05:50
Rohan
43a0161257 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-10-04 13:13:06 +05:30
gavin
f8996b64f1 fix: report ~ lead conversion time (#19234) 2019-10-03 11:37:41 +05:30
Rucha Mahabal
867443ea6d fix: produced_qty field hidden and not updated in sales order item (v11) (#19214)
* fix: produced_qty field hidden and not updated in sales order item

* fix: codacy review
2019-09-30 20:04:21 +05:30
Rohan
acdc230ef3 fix: set no-copy on some contract fields (#19207) 2019-09-30 20:04:03 +05:30
DeeMysterio
86232e4449 fix(purchase receipt): rename return/invoice to Purchase return/invoice (#19213) 2019-09-30 16:59:08 +05:30
rohitwaghchaure
78c7f03731 fix: mismatch stock value between stock balance report and stock in hand in trial balance (#19203) 2019-09-30 15:18:38 +05:30
Marica
65b99a5109 fix: Make '% Completed' 100% in Projects if no Tasks and Status is Completed (#19176) 2019-09-30 15:12:10 +05:30
rohitwaghchaure
8ec290d5ec fix: group by customer filter shows incorrect value in buying amount column for the gross profit report (#18998) 2019-09-30 10:28:10 +05:30
Nabin Hait
65a259eb81 refactor: Reposting utility of Stock ledger (#19153) 2019-09-26 16:44:02 +05:30
Sahil Khan
47420578ae Merge branch 'version-11-hotfix' into version-11 2019-09-26 13:55:31 +05:30
Sahil Khan
35d8cd9f10 bumped to version 11.1.65 2019-09-26 14:15:31 +05:50
Rucha Mahabal
1e55ac6a4f fix(Report): Sales Register (#19170) 2019-09-25 16:03:09 +05:30
Rohan
ce60dc3ea3 Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-09-25 14:45:21 +05:30
Nabin Hait
ff7a5d18d1 fix: Handling payments against credit/debit notes and party currency (#19152) 2019-09-24 19:52:06 +05:30
Rucha Mahabal
5a15dcc060 fix(Stock): item variant description (#19135) 2019-09-24 19:16:43 +05:30
Sahil Khan
cec6c87e09 Merge branch 'version-11-hotfix' into version-11 2019-09-24 18:14:44 +05:30
Sahil Khan
b2870b9426 bumped to version 11.1.64 2019-09-24 18:34:44 +05:50
rohitwaghchaure
e27600066c Merge pull request #19145 from rohitwaghchaure/fixed_imponibileimporto_for_the_previous_row_total
fix: ImponibileImporto not getting calculated properly
2019-09-24 18:11:16 +05:30
Nabin Hait
5b8c624b34 Merge branch 'version-11-hotfix' into fixed_imponibileimporto_for_the_previous_row_total 2019-09-24 11:46:24 +05:30
Anurag Mishra
9e8531d68e fix: provided delete permission (#19142) 2019-09-24 09:55:01 +05:30
Mangesh-Khairnar
ebeb137351 chore: remove unlinked letter head references (#19139) 2019-09-24 09:52:13 +05:30
Rohit Waghchaure
8c7d28a41a fix: ImponibileImporto not getting calculated properly 2019-09-23 17:39:55 +05:30
rohitwaghchaure
d90b80af86 Merge pull request #19128 from rohitwaghchaure/removed_mandatory_property_for_address_field_in_quick_entry_v11_hotfix
fix: removed mandatory property for address field in quick entry
2019-09-23 14:48:41 +05:30
Anurag Mishra
b62e17f7f2 feat: missmatching amount in GST Sales report and itemised sales report (#19119) 2019-09-20 22:59:26 +05:30
Rohit Waghchaure
ec56984e12 fix: removed mandatory property for address field in quick entry 2019-09-20 12:20:37 +05:30
Rohan
b23da53fee Merge branch 'version-11-hotfix' into v11-work-order-bugs 2019-09-18 13:24:25 +05:30
Rohan
d37a30fc47 fix: operating cost calculation in JS 2019-09-12 16:12:48 +05:30
97 changed files with 5130 additions and 4306 deletions

View File

@@ -76,5 +76,6 @@ install:
- bench --site test_site reinstall --yes
after_script:
- pip install coverage==4.5.4
- pip install python-coveralls
- coveralls -b apps/erpnext -d ../../sites/.coverage

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '11.1.63'
__version__ = '11.1.73'
def get_default_company(user=None):
'''Get default company for user'''
@@ -144,4 +144,4 @@ def is_member():
last_membership = get_last_membership()
if last_membership and getdate(last_membership.to_date) > getdate():
return True
return False
return False

View File

@@ -174,6 +174,8 @@ def make_gl_entries(doc, credit_account, debit_account, against,
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
if amount == 0: return
gl_entries = []
gl_entries.append(
doc.get_gl_dict({

View File

@@ -100,7 +100,10 @@ class Account(NestedSet):
if ancestors:
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
return
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
if not frappe.db.get_value("Account",
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
else:
descendants = get_descendants_of('Company', self.company)
if not descendants: return
@@ -114,21 +117,7 @@ class Account(NestedSet):
if not parent_acc_name_map: return
for company in descendants:
if not parent_acc_name_map.get(company):
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
.format(company, parent_acc_name))
doc = frappe.copy_doc(self)
doc.flags.ignore_root_company_validation = True
doc.update({
"company": company,
"account_currency": None,
"parent_account": parent_acc_name_map[company]
})
doc.save()
frappe.msgprint(_("Account {0} is added in the child company {1}")
.format(doc.name, company))
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
def validate_group_or_ledger(self):
if self.get("__islocal"):
@@ -170,6 +159,49 @@ class Account(NestedSet):
if frappe.db.get_value("GL Entry", {"account": self.name}):
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
for company in descendants:
if not parent_acc_name_map.get(company):
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
.format(company, parent_acc_name))
filters = {
"account_name": self.account_name,
"company": company
}
if self.account_number:
filters["account_number"] = self.account_number
child_account = frappe.db.get_value("Account", filters, 'name')
if not child_account:
doc = frappe.copy_doc(self)
doc.flags.ignore_root_company_validation = True
doc.update({
"company": company,
# parent account's currency should be passed down to child account's curreny
# if it is None, it picks it up from default company currency, which might be unintended
"account_currency": self.account_currency,
"parent_account": parent_acc_name_map[company]
})
doc.save()
frappe.msgprint(_("Account {0} is added in the child company {1}")
.format(doc.name, company))
elif child_account:
# update the parent company's value in child companies
doc = frappe.get_doc("Account", child_account)
parent_value_changed = False
for field in ['account_type', 'account_currency',
'freeze_account', 'balance_must_be']:
if doc.get(field) != self.get(field):
parent_value_changed = True
doc.set(field, self.get(field))
if parent_value_changed:
doc.save()
def convert_group_to_ledger(self):
if self.check_if_child_exists():
throw(_("Account with child nodes cannot be converted to ledger"))

View File

@@ -1,465 +1,466 @@
{
"country_code": "ae",
"name": "U.A.E - Chart of Accounts",
"country_code": "ae",
"name": "U.A.E - Chart of Accounts",
"tree": {
"Assets": {
"Current Assets": {
"Accounts Receivable": {
"Corporate Credit Cards": {
"account_type": "Receivable"
},
},
"Other Receivable": {
"Accrued Rebates Due from Suppliers": {
"account_type": "Receivable"
},
"Accured Income from Suppliers": {
},
"Accrued Income from Suppliers": {
"account_type": "Receivable"
},
},
"Other Debtors": {
"account_type": "Receivable"
},
},
"account_type": "Receivable"
},
},
"Post Dated Cheques Received": {
"account_type": "Receivable"
},
},
"Staff Receivable": {
"account_type": "Receivable"
},
},
"Trade Receivable": {
"account_type": "Receivable"
},
},
"Trade in Opening Fees": {
"account_type": "Receivable"
},
},
"account_type": "Receivable"
},
},
"Cash in Hand & Banks": {
"Banks": {
"Bank Margin On LC & LG": {},
"Banks Blocked Deposits": {},
"Banks Call Deposit Accounts": {},
"Bank Margin On LC & LG": {},
"Banks Blocked Deposits": {},
"Banks Call Deposit Accounts": {},
"Banks Current Accounts": {
"account_type": "Bank"
},
},
"account_type": "Bank"
},
},
"Cash in Hand": {
"Cash in Safe": {
"Main Safe": {
"account_type": "Cash"
},
},
"Main Safe - Foreign Currency": {
"account_type": "Cash"
}
},
},
"Petty Cash": {
"Petty Cash - Admininistration": {
"account_type": "Cash"
},
},
"Petty Cash - Others": {
"account_type": "Cash"
}
},
},
"account_type": "Cash"
},
},
"Cash in Transit": {
"Credit Cards": {
"Gateway Credit Cards": {
"account_type": "Bank"
},
},
"Manual Visa & Master Cards": {
"account_type": "Bank"
},
},
"PayPal Account": {
"account_type": "Bank"
},
},
"Visa & Master Credit Cards": {
"account_type": "Bank"
}
}
}
},
},
"Inventory": {
"Consigned Stock": {
"Handling Difference in Inventory": {
"account_type": "Stock Adjustment"
},
"Items Delivered to Customs on temprary Base": {}
},
"Handling Difference in Inventory": {},
"Items Delivered to Customs on temporary Base": {}
},
"Stock in Hand": {
"account_type": "Stock"
}
},
"Perliminary and Preoperating Expenses": {
},
"Preliminary and Preoperating Expenses": {
"Preoperating Expenses": {}
},
},
"Prepayments & Deposits": {
"Deposits": {
"Deposit - Office Rent": {},
"Deposit Others": {},
"Deposit to Immigration (Visa)": {},
"Deposit - Office Rent": {},
"Deposit Others": {},
"Deposit to Immigration (Visa)": {},
"Deposits - Customs": {}
},
},
"Prepaid Taxes": {
"Sales Taxes Receivables": {},
"Sales Taxes Receivables": {},
"Withholding Tax Receivables": {}
},
},
"Prepayments": {
"Other Prepayments": {},
"PrePaid Advertisement Expenses": {},
"Prepaid Bank Guarantee": {},
"Prepaid Consultancy Fees": {},
"Prepaid Employees Housing": {},
"Prepaid Finance charge for Loans": {},
"Prepaid Legal Fees": {},
"Prepaid License Fees": {},
"Prepaid Life Insurance": {},
"Prepaid Maintenance": {},
"Prepaid Medical Insurance": {},
"Prepaid Office Rent": {},
"Prepaid Other Insurance": {},
"Prepaid Schooling Fees": {},
"Prepaid Site Hosting Fees": {},
"Other Prepayments": {},
"PrePaid Advertisement Expenses": {},
"Prepaid Bank Guarantee": {},
"Prepaid Consultancy Fees": {},
"Prepaid Employees Housing": {},
"Prepaid Finance charge for Loans": {},
"Prepaid Legal Fees": {},
"Prepaid License Fees": {},
"Prepaid Life Insurance": {},
"Prepaid Maintenance": {},
"Prepaid Medical Insurance": {},
"Prepaid Office Rent": {},
"Prepaid Other Insurance": {},
"Prepaid Schooling Fees": {},
"Prepaid Site Hosting Fees": {},
"Prepaid Sponsorship Fees": {}
}
}
},
},
"Long Term Assets": {
"Fixed Assets": {
"Accumulated Depreciation": {
"Acc. Depreciation of Motor Vehicles": {
"account_type": "Accumulated Depreciation"
},
},
"Acc. Deprn.Computer Hardware & Software": {
"account_type": "Accumulated Depreciation"
},
},
"Acc.Deprn.of Furniture & Office Equipment": {
"account_type": "Accumulated Depreciation"
},
},
"Amortisation on Leasehold Improvement": {
"account_type": "Accumulated Depreciation"
},
},
"account_type": "Accumulated Depreciation"
},
},
"Fixed Assets (Cost Price)": {
"Computer Hardware & Software": {
"account_type": "Fixed Asset"
},
},
"Furniture and Equipment": {
"account_type": "Fixed Asset"
},
"Leasehold Improvement": {},
"Motor Vehicules": {
},
"Leasehold Improvement": {},
"Motor Vehicles": {
"account_type": "Fixed Asset"
},
"Work In Progrees": {},
},
"Work In Progress": {},
"account_type": "Fixed Asset"
}
},
},
"Intangible Assets": {
"Computer Card Renewal": {},
"Dispoal of Outlets": {},
"Computer Card Renewal": {},
"Disposal of Outlets": {},
"Registration of Trademarks": {}
},
"Intercompany Accounts": {},
},
"Intercompany Accounts": {},
"Investments": {
"Investments in Subsidiaries": {}
}
},
},
"root_type": "Asset"
},
},
"Closing And Temporary Accounts": {
"Closing Accounts": {
"Closing Account": {}
},
},
"root_type": "Liability"
},
},
"Expenses": {
"Commercial Expenses": {
"Consultancy Fees": {},
"Consultancy Fees": {},
"Provision for Doubtful Debts": {}
},
},
"Cost of Sale": {
"Cost Of Goods Sold": {
"Cost Of Goods Sold I/C Sales": {},
"Cost Of Goods Sold I/C Sales": {},
"Cost of Goods Sold in Trading": {
"account_type": "Cost of Goods Sold"
},
},
"account_type": "Cost of Goods Sold"
},
},
"Expenses Included In Valuation": {
"account_type": "Expenses Included In Valuation"
},
"Stock Adjustment": {
"account_type": "Stock Adjustment"
}
},
},
"Depreciation": {
"Depreciation & Amortization": {
"Amortization on Leasehold Improvement": {},
"Amortization on Leasehold Improvement": {},
"Depreciation Of Computer Hard & Soft": {
"account_type": "Depreciation"
},
},
"Depreciation Of Furniture & Office Equipment\n\t\t\t": {
"account_type": "Depreciation"
},
},
"Depreciation Of Motor Vehicles": {
"account_type": "Depreciation"
}
}
},
},
"Direct Expenses": {
"Financial Charges": {
"Air Miles Card Charges": {},
"Amex Credit Cards Charges": {},
"Bank Finance & Loan Charges": {},
"Credit Card Charges": {},
"Credit Card Swipe Charges": {},
"Air Miles Card Charges": {},
"Amex Credit Cards Charges": {},
"Bank Finance & Loan Charges": {},
"Credit Card Charges": {},
"Credit Card Swipe Charges": {},
"PayPal Charges": {}
}
},
},
"MISC Charges": {
"Other Charges": {
"Captial Loss": {
"Disposal of Business Branch": {},
"Loss On Fixed Assets Disposal": {},
"Capital Loss": {
"Disposal of Business Branch": {},
"Loss On Fixed Assets Disposal": {},
"Loss on Difference on Exchange": {}
},
},
"Other Non Operating Exp": {
"Other Non Operating Expenses": {}
},
},
"Previous Year Adjustments": {
"Previous Year Adjustments Account": {}
},
},
"Royalty Fees": {
"Royalty to Parent Co.": {}
},
},
"Tax / Zakat Expenses": {
"Income Tax": {
"account_type": "Tax"
},
"Zakat": {},
},
"Zakat": {},
"account_type": "Tax"
}
}
},
},
"Share Resources": {
"Share Resource Expenses Account": {}
},
},
"Store Operating Expenses": {
"Selling, General & Admin Expenses": {
"Advertising Expenses": {
"Other - Advertising Expenses": {}
},
},
"Bank & Finance Charges": {
"Other Bank Charges": {}
},
},
"Communications": {
"Courrier": {},
"Others - Communication": {},
"Telephone": {},
"Courier": {},
"Others - Communication": {},
"Telephone": {},
"Web Site Hosting Fees": {}
},
},
"Office & Various Expenses": {
"Cleaning": {},
"Convoyance Expenses": {},
"Gifts & Donations": {},
"Insurance": {},
"Kitchen and Buffet Expenses": {},
"Maintenance": {},
"Others - Office Various Expenses": {},
"Security & Guard": {},
"Stationary From Suppliers": {},
"Stationary Out Of Stock": {},
"Subscriptions": {},
"Training": {},
"Cleaning": {},
"Conveyance Expenses": {},
"Gifts & Donations": {},
"Insurance": {},
"Kitchen and Buffet Expenses": {},
"Maintenance": {},
"Others - Office Various Expenses": {},
"Security & Guard": {},
"Stationary From Suppliers": {},
"Stationary Out Of Stock": {},
"Subscriptions": {},
"Training": {},
"Vehicle Expenses": {}
},
},
"Personnel Cost": {
"Basic Salary": {},
"End Of Service Indemnity": {},
"Housing Allowance": {},
"Leave Salary": {},
"Leave Ticket": {},
"Life Insurance": {},
"Medical Insurance": {},
"Personnel Cost Others": {},
"Sales Commission": {},
"Staff School Allowances": {},
"Transportation Allowance": {},
"Uniform": {},
"Basic Salary": {},
"End Of Service Indemnity": {},
"Housing Allowance": {},
"Leave Salary": {},
"Leave Ticket": {},
"Life Insurance": {},
"Medical Insurance": {},
"Personnel Cost Others": {},
"Sales Commission": {},
"Staff School Allowances": {},
"Transportation Allowance": {},
"Uniform": {},
"Visa Expenses": {}
},
},
"Professional & Legal Fees": {
"Audit Fees": {},
"Legal fees": {},
"Others - Professional Fees": {},
"Sponsorship Fees": {},
"Audit Fees": {},
"Legal fees": {},
"Others - Professional Fees": {},
"Sponsorship Fees": {},
"Trade License Fees": {}
},
},
"Provision & Write Off": {
"Amortisation of Preoperating Expenses": {},
"Cash Shortage": {},
"Others - Provision & Write off": {},
"Write Off Inventory": {},
"Amortisation of Preoperating Expenses": {},
"Cash Shortage": {},
"Others - Provision & Write off": {},
"Write Off Inventory": {},
"Write Off Receivables & Payables": {}
},
},
"Rent Expenses": {
"Office Rent": {},
"Office Rent": {},
"Warehouse Rent": {}
},
},
"Travel Expenses": {
"Air tickets": {},
"Hotel": {},
"Meals": {},
"Others": {},
"Air tickets": {},
"Hotel": {},
"Meals": {},
"Others": {},
"Per Diem": {}
},
},
"Utilities": {
"Other Utility Cahrges": {},
"Other Utility Cahrges": {},
"Water & Electricity": {}
}
}
},
},
"root_type": "Expense"
},
},
"Liabilities": {
"Current Liabilities": {
"Accounts Payable": {
"Payables": {
"Advance Paybale to Suppliers": {
"account_type": "Payable"
},
},
"Consigned Payable": {
"account_type": "Payable"
},
},
"Other Payable": {
"account_type": "Payable"
},
},
"Post Dated Cheques Paid": {
"account_type": "Payable"
},
"Staff Payable": {},
},
"Staff Payable": {},
"Suppliers Price Protection": {
"account_type": "Payable"
},
},
"Trade Payable": {
"account_type": "Payable"
},
},
"account_type": "Payable"
}
},
},
"Accruals & Provisions": {
"Accruals": {
"Accrued Personnel Cost": {
"Accrued - Commissions": {},
"Accrued - Leave Salary": {},
"Accrued - Leave Tickets": {},
"Accrued - Salaries": {},
"Accrued Other Personnel Cost": {},
"Accrued Salaries Increment": {},
"Accrued - Commissions": {},
"Accrued - Leave Salary": {},
"Accrued - Leave Tickets": {},
"Accrued - Salaries": {},
"Accrued Other Personnel Cost": {},
"Accrued Salaries Increment": {},
"Accrued-Staff Bonus": {}
}
},
},
"Accrued Expenses": {
"Accrued Other Expenses": {
"Accrued - Audit Fees": {},
"Accrued - Office Rent": {},
"Accrued - Sponsorship": {},
"Accrued - Telephone": {},
"Accrued - Utilities": {},
"Accrued - Audit Fees": {},
"Accrued - Office Rent": {},
"Accrued - Sponsorship": {},
"Accrued - Telephone": {},
"Accrued - Utilities": {},
"Accrued Others": {}
}
},
},
"Other Current Liabilities": {
"Accrued Dubai Customs": {},
"Deferred income": {},
"Accrued Dubai Customs": {},
"Deferred income": {},
"Shipping & Handling": {}
},
},
"Provisions": {
"Tax Payables": {
"Income Tax Payable": {},
"Sales Tax Payable": {},
"Income Tax Payable": {},
"Sales Tax Payable": {},
"Withholding Tax Payable": {}
}
},
},
"Short Term Loan": {}
},
},
"Duties and Taxes": {
"account_type": "Tax",
"account_type": "Tax",
"is_group": 1
},
},
"Reservations & Credit Notes": {
"Credit Notes": {
"Credit Notes to Customers": {},
"Credit Notes to Customers": {},
"Reservations": {}
}
},
},
"Stock Liabilities": {
"Stock Received But Not Billed": {
"account_type": "Stock Received But Not Billed"
}
},
},
"Unearned Income": {}
},
},
"Long Term Liabilities": {
"Long Term Loans & Provisions": {}
},
},
"root_type": "Liability"
},
},
"Revenue": {
"Direct Revenue": {
"Other Direct Revenue": {
"Other Revenue - Operating": {
"Advertising Income": {},
"Branding Income": {},
"Early Setmt Margin from Suppliers": {},
"Marketing Rebate from Suppliers": {},
"Rebate from Suppliers": {},
"Service Income": {},
"Advertising Income": {},
"Branding Income": {},
"Early Setmt Margin from Suppliers": {},
"Marketing Rebate from Suppliers": {},
"Rebate from Suppliers": {},
"Service Income": {},
"Space Rental Income": {}
}
}
},
},
"Indirect Revenue": {
"Other Indirect Revenue": {
"Capital Gain": {},
"Excess In Till": {},
"Gain On Difference Of Exchange": {},
"Management Consultancy Fees": {},
"Capital Gain": {},
"Excess In Till": {},
"Gain On Difference Of Exchange": {},
"Management Consultancy Fees": {},
"Other Income": {}
},
},
"Other Revenue - Non Operating": {
"Interest Revenue": {},
"Interest from FD": {},
"Products Listing Fees from Suppliers": {},
"Interest Revenue": {},
"Interest from FD": {},
"Products Listing Fees from Suppliers": {},
"Trade Opening Fees from suppliers": {}
}
},
},
"Sales": {
"Sales from Other Regions": {
"Sales from Other Region": {}
},
},
"Sales of same region": {
"Management Consultancy Fees 1": {},
"Sales Account": {},
"Management Consultancy Fees 1": {},
"Sales Account": {},
"Sales of I/C": {}
}
},
},
"root_type": "Income"
},
},
"Share Holder Equity": {
"Capital": {
"Contributed Capital": {},
"Share Capital": {},
"Shareholders Current A/c": {},
"Sub Ordinated Loan": {},
"Contributed Capital": {},
"Share Capital": {},
"Shareholders Current A/c": {},
"Sub Ordinated Loan": {},
"Treasury Stocks": {}
},
},
"Retained Earnings": {
"Current Year Results": {},
"Dividends Paid": {},
"Current Year Results": {},
"Dividends Paid": {},
"Previous Years Results": {}
},
"account_type": "Equity",
},
"account_type": "Equity",
"root_type": "Equity"
}
}

View File

@@ -92,10 +92,10 @@ frappe.ui.form.on("Journal Entry", {
multi_currency: function(frm) {
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
},
posting_date: function(frm) {
if(!frm.doc.multi_currency || !frm.doc.posting_date) return;
$.each(frm.doc.accounts || [], function(i, row) {
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
})
@@ -234,7 +234,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
out.filters.push([jvd.reference_type, "per_billed", "<", 100]);
}
if(jvd.party_type && jvd.party) {
var party_field = "";
if(jvd.reference_type.indexOf("Sales")===0) {
@@ -382,7 +382,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
});
refresh_field("accounts");
}
if((!(doc.accounts || []).length) || ((doc.accounts || []).length==1 && !doc.accounts[0].account)) {
if(in_list(["Bank Entry", "Cash Entry"], doc.voucher_type)) {
return frappe.call({
@@ -390,7 +390,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (doc.voucher_type=="Bank Entry" ?
"Bank" : (doc.voucher_type=="Cash" ? "Cash" : null)),
"Bank" : (doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": doc.company
},
callback: function(r) {
@@ -442,7 +442,7 @@ frappe.ui.form.on("Journal Entry Account", {
account: function(frm, dt, dn) {
erpnext.journal_entry.set_account_balance(frm, dt, dn);
},
debit_in_account_currency: function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
},

View File

@@ -294,7 +294,7 @@ frappe.ui.form.on('Payment Entry', {
() => {
frm.set_party_account_based_on_party = false;
if (r.message.bank_account) {
frm.set_value("bank_account", r.message.bank_account);
frm.set_value("party_bank_account", r.message.bank_account);
}
}
]);

View File

@@ -1791,6 +1791,41 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Draft",
"fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "\nDraft\nSubmitted\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -2205,7 +2240,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-27 17:39:54.163016",
"modified": "2019-11-06 15:15:45.223497",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -60,6 +60,7 @@ class PaymentEntry(AccountsController):
self.validate_duplicate_entry()
self.validate_allocated_amount()
self.ensure_supplier_is_not_blocked()
self.set_status()
def on_submit(self):
self.setup_party_account_field()
@@ -69,6 +70,7 @@ class PaymentEntry(AccountsController):
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_expense_claim()
self.set_status()
def on_cancel(self):
@@ -78,6 +80,7 @@ class PaymentEntry(AccountsController):
self.update_advance_paid()
self.update_expense_claim()
self.delink_advance_entry_references()
self.set_status()
def update_outstanding_amounts(self):
self.set_missing_ref_details(force=True)
@@ -274,6 +277,14 @@ class PaymentEntry(AccountsController):
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
.format(d.reference_name, dr_or_cr))
def set_status(self):
if self.docstatus == 2:
self.status = 'Cancelled'
elif self.docstatus == 1:
self.status = 'Submitted'
else:
self.status = 'Draft'
def set_amounts(self):
self.set_amounts_in_company_currency()
self.set_total_allocated_amount()

View File

@@ -250,7 +250,7 @@ class PurchaseInvoice(BuyingController):
def set_against_expense_account(self):
against_accounts = []
for item in self.get("items"):
if item.expense_account not in against_accounts:
if item.expense_account and (item.expense_account not in against_accounts):
against_accounts.append(item.expense_account)
self.against_expense_account = ",".join(against_accounts)
@@ -363,7 +363,7 @@ class PurchaseInvoice(BuyingController):
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False)
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
if update_outstanding == "No":
update_outstanding_amt(self.credit_to, "Supplier", self.supplier,
@@ -750,7 +750,11 @@ class PurchaseInvoice(BuyingController):
)
def make_gle_for_rounding_adjustment(self, gl_entries):
if self.rounding_adjustment:
# if rounding adjustment in small and conversion rate is also small then
# base_rounding_adjustment may become zero due to small precision
# eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
# then base_rounding_adjustment becomes zero and error is thrown in GL Entry
if self.rounding_adjustment and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)

View File

@@ -350,7 +350,7 @@ class SalesInvoice(SellingController):
timesheet.calculate_percentage_billed()
timesheet.flags.ignore_validate_update_after_submit = True
timesheet.set_status()
timesheet.save()
timesheet.save(ignore_permissions=True)
def update_time_sheet_detail(self, timesheet, args, sales_invoice):
for data in timesheet.time_logs:
@@ -699,7 +699,7 @@ class SalesInvoice(SellingController):
cint(self.redeem_loyalty_points)) else "Yes"
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False)
update_outstanding=update_outstanding, merge_entries=False, from_repost=from_repost)
if update_outstanding == "No":
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
@@ -944,7 +944,7 @@ class SalesInvoice(SellingController):
)
def make_gle_for_rounding_adjustment(self, gl_entries):
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")):
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
@@ -992,10 +992,8 @@ class SalesInvoice(SellingController):
continue
for serial_no in item.serial_no.split("\n"):
if serial_no and frappe.db.exists('Serial No', serial_no):
sno = frappe.get_doc('Serial No', serial_no)
sno.sales_invoice = invoice
sno.db_update()
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
def validate_serial_numbers(self):
"""
@@ -1041,12 +1039,18 @@ class SalesInvoice(SellingController):
continue
for serial_no in item.serial_no.split("\n"):
sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice")
if sales_invoice and self.name != sales_invoice:
sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company")
serial_no_details = frappe.db.get_value("Serial No", serial_no,
["sales_invoice", "item_code"], as_dict=1)
if not serial_no_details:
continue
if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \
and self.name != serial_no_details.sales_invoice:
sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
if sales_invoice_company == self.company:
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
.format(serial_no, sales_invoice)))
.format(serial_no, serial_no_details.sales_invoice)))
def update_project(self):
if self.project:

View File

@@ -16,7 +16,7 @@ frappe.ui.form.on('Share Transfer', {
};
};
});
if (frm.doc.docstatus == 1) {
if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account ) {
frm.add_custom_button(__('Make Journal Entry'), function () {
erpnext.share_transfer.make_jv(frm);
});
@@ -92,6 +92,7 @@ erpnext.share_transfer.make_jv = function (frm) {
debit_applicant_type = "Shareholder";
debit_applicant = frm.doc.from_shareholder;
}
frappe.call({
args: {
"company": frm.doc.company,

View File

@@ -292,11 +292,14 @@ def make_jv_entry( company, account, amount, payment_account,\
"party_type": debit_applicant_type,
"party": debit_applicant,
})
account_amt_list.append({
"account": payment_account,
"credit_in_account_currency": amount,
"party_type": credit_applicant_type,
"party": credit_applicant,
})
journal_entry.set("accounts", account_amt_list)
return journal_entry.as_dict()

View File

@@ -9,7 +9,7 @@
</div>
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
{% if doc.get(df.fieldname) != None -%}
{{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
{{ frappe.utils.fmt_money((doc[df.fieldname])|abs, currency=doc.currency) }}
{% endif %}
</div>
</div>
@@ -26,7 +26,7 @@
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ charge.get_formatted("description") }}</label></div>
<div class="col-xs-7 text-right">
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
{{ frappe.utils.fmt_money((charge.tax_amount)|abs, currency=doc.currency) }}
</div>
</div>
{%- endif -%}
@@ -65,8 +65,10 @@
{% for tdf in visible_columns %}
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
{% if tdf.fieldtype == 'Currency' %}
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}</div></td>
{% if tdf.fieldname == 'qty' %}
<div class="value">{{ (d[tdf.fieldname])|abs }}</div></td>
{% elif tdf.fieldtype == 'Currency' %}
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|abs, currency=doc.currency) }}</div></td>
{% else %}
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
{% endif %}
@@ -117,7 +119,7 @@
{{ render_currency(df, doc) }}
{% elif df.fieldtype =='Table' %}
{{ render_table(df, doc)}}
{% elif doc[df.fieldname] %}
{% elif doc[df.fieldname] and df.fieldname != 'total_qty' %}
{{ render_field(df, doc) }}
{% endif %}
{% endfor %}

View File

@@ -58,8 +58,8 @@ class ReceivablePayableReport(object):
self.invoices = set()
def get_data(self):
t1 = now()
self.get_gl_entries()
self.get_sales_invoices_or_customers_based_on_sales_person()
self.voucher_balance = OrderedDict()
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
@@ -72,6 +72,9 @@ class ReceivablePayableReport(object):
# fetch future payments against invoices
self.get_future_payments()
# Get return entries
self.get_return_entries()
self.data = []
for gle in self.gl_entries:
self.update_voucher_balance(gle)
@@ -90,6 +93,7 @@ class ReceivablePayableReport(object):
party = gle.party,
posting_date = gle.posting_date,
remarks = gle.remarks,
account_currency = gle.account_currency,
invoiced = 0.0,
paid = 0.0,
credit_note = 0.0,
@@ -99,13 +103,18 @@ class ReceivablePayableReport(object):
def get_invoices(self, gle):
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
self.invoices.add(gle.voucher_no)
if self.filters.get("sales_person"):
if gle.voucher_no in self.sales_person_records.get("Sales Invoice", []) \
or gle.party in self.sales_person_records.get("Customer", []):
self.invoices.add(gle.voucher_no)
else:
self.invoices.add(gle.voucher_no)
def update_voucher_balance(self, gle):
# get the row where this balance needs to be updated
# if its a payment, it will return the linked invoice or will be considered as advance
row = self.get_voucher_balance(gle)
if not row: return
# gle_balance will be the total "debit - credit" for receivable type reports and
# and vice-versa for payable type reports
gle_balance = self.get_gle_balance(gle)
@@ -126,11 +135,27 @@ class ReceivablePayableReport(object):
row.paid -= gle_balance
def get_voucher_balance(self, gle):
voucher_balance = None
if self.filters.get("sales_person"):
against_voucher = gle.against_voucher or gle.voucher_no
if not (gle.party in self.sales_person_records.get("Customer", []) or \
against_voucher in self.sales_person_records.get("Sales Invoice", [])):
return
voucher_balance = None
if gle.against_voucher:
# find invoice
voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party))
against_voucher = gle.against_voucher
# If payment is made against credit note
# and credit note is made against a Sales Invoice
# then consider the payment against original sales invoice.
if gle.against_voucher_type in ('Sales Invoice', 'Purchase Invoice'):
if gle.against_voucher in self.return_entries:
return_against = self.return_entries.get(gle.against_voucher)
if return_against:
against_voucher = return_against
voucher_balance = self.voucher_balance.get((gle.against_voucher_type, against_voucher, gle.party))
if not voucher_balance:
# no invoice, this is an invoice / stand-alone payment / credit note
@@ -174,7 +199,11 @@ class ReceivablePayableReport(object):
self.data.append(row)
def set_invoice_details(self, row):
row.update(self.invoice_details.get(row.voucher_no, {}))
invoice_details = self.invoice_details.get(row.voucher_no, {})
if row.due_date:
invoice_details.pop("due_date", None)
row.update(invoice_details)
if row.voucher_type == 'Sales Invoice':
if self.filters.show_delivery_notes:
self.set_delivery_notes(row)
@@ -257,7 +286,6 @@ class ReceivablePayableReport(object):
# customer / supplier name
party_details = self.get_party_details(row.party)
row.update(party_details)
if self.filters.get(scrub(self.filters.party_type)):
row.currency = row.account_currency
else:
@@ -422,6 +450,19 @@ class ReceivablePayableReport(object):
if row.future_ref:
row.future_ref = ', '.join(row.future_ref)
def get_return_entries(self):
doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
filters={
'is_return': 1,
'docstatus': 1
}
party_field = scrub(self.filters.party_type)
if self.filters.get(party_field):
filters.update({party_field: self.filters.get(party_field)})
self.return_entries = frappe._dict(
frappe.get_all(doctype, filters, ['name', 'return_against'], as_list=1)
)
def set_ageing(self, row):
if self.filters.ageing_based_on == "Due Date":
entry_date = row.due_date
@@ -482,6 +523,22 @@ class ReceivablePayableReport(object):
order by posting_date, party"""
.format(select_fields, conditions), values, as_dict=True)
def get_sales_invoices_or_customers_based_on_sales_person(self):
if self.filters.get("sales_person"):
lft, rgt = frappe.db.get_value("Sales Person",
self.filters.get("sales_person"), ["lft", "rgt"])
records = frappe.db.sql("""
select distinct parent, parenttype
from `tabSales Team` steam
where parenttype in ('Customer', 'Sales Invoice')
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
""", (lft, rgt), as_dict=1)
self.sales_person_records = frappe._dict()
for d in records:
self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
def prepare_conditions(self):
conditions = [""]
values = [self.party_type, self.filters.report_date]
@@ -532,16 +589,6 @@ class ReceivablePayableReport(object):
conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
values.append(self.filters.get("sales_partner"))
if self.filters.get("sales_person"):
lft, rgt = frappe.db.get_value("Sales Person",
self.filters.get("sales_person"), ["lft", "rgt"])
conditions.append("""exists(select name from `tabSales Team` steam where
steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
def add_supplier_filters(self, conditions, values):
if self.filters.get("supplier_group"):
conditions.append("""party in (select name from tabSupplier
@@ -677,11 +724,11 @@ class ReceivablePayableReport(object):
def get_chart_data(self):
rows = []
for row in self.data:
rows.append(
{
'values': [row.range1, row.range2, row.range3, row.range4, row.range5]
}
)
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
precision = cint(frappe.db.get_default("float_precision")) or 2
rows.append({
'values': [flt(val, precision) for val in values]
})
self.chart = {
"data": {

View File

@@ -36,6 +36,9 @@ class AccountsReceivableSummary(ReceivablePayableReport):
self.filters.report_date) or {}
for party, party_dict in iteritems(self.party_total):
if party_dict.outstanding == 0:
continue
row = frappe._dict()
row.party = party
@@ -132,4 +135,4 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
self.add_column(label=label, fieldname='range' + str(i+1))
self.add_column(label=label, fieldname='range' + str(i+1))

View File

@@ -4,126 +4,141 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import formatdate, getdate, flt, add_days
from frappe.utils import formatdate, flt, add_days
def execute(filters=None):
filters.day_before_from_date = add_days(filters.from_date, -1)
columns, data = get_columns(filters), get_data(filters)
return columns, data
def get_data(filters):
data = []
asset_categories = get_asset_categories(filters)
assets = get_assets(filters)
asset_costs = get_asset_costs(assets, filters)
asset_depreciations = get_accumulated_depreciations(assets, filters)
for asset_category in asset_categories:
row = frappe._dict()
row.asset_category = asset_category
row.update(asset_costs.get(asset_category))
# row.asset_category = asset_category
row.update(asset_category)
row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) -
flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
row.update(next(asset for asset in assets if asset["asset_category"] == asset_category.get("asset_category", "")))
row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
flt(row.accumulated_depreciation_as_on_from_date))
row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
flt(row.accumulated_depreciation_as_on_to_date))
row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase)
- flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
row.update(asset_depreciations.get(asset_category))
row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
flt(row.accumulated_depreciation_as_on_from_date))
row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
flt(row.accumulated_depreciation_as_on_to_date))
data.append(row)
return data
def get_asset_categories(filters):
return frappe.db.sql_list("""
select distinct asset_category from `tabAsset`
where docstatus=1 and company=%s and purchase_date <= %s
""", (filters.company, filters.to_date))
return frappe.db.sql("""
SELECT asset_category,
ifnull(sum(case when purchase_date < %(from_date)s then
case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
gross_purchase_amount
else
0
end
else
0
end), 0) as cost_as_on_from_date,
ifnull(sum(case when purchase_date >= %(from_date)s then
gross_purchase_amount
else
0
end), 0) as cost_of_new_purchase,
ifnull(sum(case when ifnull(disposal_date, 0) != 0
and disposal_date >= %(from_date)s
and disposal_date <= %(to_date)s then
case when status = "Sold" then
gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_sold_asset,
ifnull(sum(case when ifnull(disposal_date, 0) != 0
and disposal_date >= %(from_date)s
and disposal_date <= %(to_date)s then
case when status = "Scrapped" then
gross_purchase_amount
else
0
end
else
0
end), 0) as cost_of_scrapped_asset
from `tabAsset`
where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s
group by asset_category
""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
def get_assets(filters):
return frappe.db.sql("""
select name, asset_category, purchase_date, gross_purchase_amount, disposal_date, status
from `tabAsset`
where docstatus=1 and company=%s and purchase_date <= %s""",
(filters.company, filters.to_date), as_dict=1)
def get_asset_costs(assets, filters):
asset_costs = frappe._dict()
for d in assets:
asset_costs.setdefault(d.asset_category, frappe._dict({
"cost_as_on_from_date": 0,
"cost_of_new_purchase": 0,
"cost_of_sold_asset": 0,
"cost_of_scrapped_asset": 0
}))
costs = asset_costs[d.asset_category]
if getdate(d.purchase_date) < getdate(filters.from_date):
if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date):
costs.cost_as_on_from_date += flt(d.gross_purchase_amount)
else:
costs.cost_of_new_purchase += flt(d.gross_purchase_amount)
if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \
and getdate(d.disposal_date) <= getdate(filters.to_date):
if d.status == "Sold":
costs.cost_of_sold_asset += flt(d.gross_purchase_amount)
elif d.status == "Scrapped":
costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount)
return asset_costs
def get_accumulated_depreciations(assets, filters):
asset_depreciations = frappe._dict()
for d in assets:
asset = frappe.get_doc("Asset", d.name)
if d.asset_category in asset_depreciations:
asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation
else:
asset_depreciations.setdefault(d.asset_category, frappe._dict({
"accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
"depreciation_amount_during_the_period": 0,
"depreciation_eliminated_during_the_period": 0
}))
SELECT results.asset_category,
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
from (SELECT a.asset_category,
ifnull(sum(a.opening_accumulated_depreciation +
case when ds.schedule_date < %(from_date)s and
(ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
ds.depreciation_amount
else
0
end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
ds.depreciation_amount
else
0
end), 0) as depreciation_eliminated_during_the_period,
depr = asset_depreciations[d.asset_category]
ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
ds.depreciation_amount
else
0
end), 0) as depreciation_amount_during_the_period
from `tabAsset` a, `tabDepreciation Schedule` ds
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent
group by a.asset_category
union
SELECT a.asset_category,
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
0
else
a.opening_accumulated_depreciation
end), 0) as accumulated_depreciation_as_on_from_date,
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
a.opening_accumulated_depreciation
else
0
end), 0) as depreciation_eliminated_during_the_period,
0 as depreciation_amount_during_the_period
from `tabAsset` a
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s
and not exists(select * from `tabDepreciation Schedule` ds where a.name = ds.parent)
group by a.asset_category) as results
group by results.asset_category
""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
if not asset.schedules: # if no schedule,
if asset.disposal_date:
# and disposal is NOT within the period, then opening accumulated depreciation not included
if getdate(asset.disposal_date) < getdate(filters.from_date) or getdate(asset.disposal_date) > getdate(filters.to_date):
asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] = 0
# if no schedule, and disposal is within period, accumulated dep is the amount eliminated
if getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
depr.depreciation_eliminated_during_the_period += asset.opening_accumulated_depreciation
for schedule in asset.get("schedules"):
if getdate(schedule.schedule_date) < getdate(filters.from_date):
if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date):
depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount)
elif getdate(schedule.schedule_date) <= getdate(filters.to_date):
if not asset.disposal_date:
depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
else:
if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
if asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
depr.depreciation_eliminated_during_the_period += flt(schedule.depreciation_amount)
return asset_depreciations
def get_columns(filters):
return [
{

View File

@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Balance Sheet"] = erpnext.financial_statements;
frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "accumulated_values",

View File

@@ -154,28 +154,31 @@ class GrossProfitGenerator(object):
def get_average_rate_based_on_group_by(self):
# sum buying / selling totals for group
for key in list(self.grouped):
for i, row in enumerate(self.grouped[key]):
if row.parent in self.returned_invoices \
and row.item_code in self.returned_invoices[row.parent]:
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
for returned_item_row in returned_item_rows:
row.qty += returned_item_row.qty
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
row.buying_amount = flt(row.qty * row.buying_rate, self.currency_precision)
if i==0:
new_row = row
elif self.filters.get("group_by") != "Invoice":
new_row.qty += row.qty
new_row.buying_amount += flt(row.buying_amount, self.currency_precision)
new_row.base_amount += flt(row.base_amount, self.currency_precision)
if self.filters.get("group_by") == "Invoice" and (row.qty or row.base_amount):
self.grouped_data_based_on_group_by(row)
if self.filters.get("group_by") != "Invoice":
for i, row in enumerate(self.grouped[key]):
if i==0:
new_row = row
else:
new_row.qty += row.qty
new_row.buying_amount += flt(row.buying_amount, self.currency_precision)
new_row.base_amount += flt(row.base_amount, self.currency_precision)
new_row = self.set_average_rate(new_row)
self.grouped_data.append(new_row)
else:
for i, row in enumerate(self.grouped[key]):
if row.parent in self.returned_invoices \
and row.item_code in self.returned_invoices[row.parent]:
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
for returned_item_row in returned_item_rows:
row.qty += returned_item_row.qty
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
row.buying_amount = flt(row.qty * row.buying_rate, self.currency_precision)
if row.qty or row.base_amount:
row = self.set_average_rate(row)
self.grouped_data.append(row)
self.grouped_data_based_on_group_by(new_row)
def grouped_data_based_on_group_by(self, row):
row = self.set_average_rate(row)
self.grouped_data.append(row)
def set_average_rate(self, new_row):
new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount, self.currency_precision)
@@ -204,10 +207,7 @@ class GrossProfitGenerator(object):
.setdefault(inv.item_code, []).append(inv)
def skip_row(self, row, product_bundles):
if self.filters.get("group_by") != "Invoice":
if not row.get(scrub(self.filters.get("group_by", ""))):
return True
elif row.get("is_return") == 1:
if row.get("is_return") == 1:
return True
def get_buying_amount_from_product_bundle(self, row, product_bundle):

View File

@@ -17,7 +17,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
columns = get_columns(additional_table_columns)
company_currency = erpnext.get_company_currency(filters.get('company'))
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
item_list = get_items(filters, additional_query_columns)
if item_list:

View File

@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe.model.meta import get_field_precision
from frappe import msgprint, _
def execute(filters=None):
@@ -67,7 +68,8 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
total_tax = 0
for tax_acc in tax_accounts:
if tax_acc not in income_accounts:
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc))
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
total_tax += tax_amount
row.append(tax_amount)

View File

@@ -5,9 +5,8 @@
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Capital Traders",
"modified": "2018-12-12 05:10:02.987274",
"is_standard": "Yes",
"modified": "2019-02-12 05:10:02.987274",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Supplier Ledger Summary",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-08-21 11:25:00.551823",
"modified": "2018-09-21 11:25:00.551823",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Computation Summary",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-08-21 11:33:40.804532",
"modified": "2019-09-24 13:46:16.473711",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Payable Monthly",

View File

@@ -75,8 +75,7 @@ def get_data(filters):
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row, parent_children_map, company_currency)
data = filter_out_zero_value_rows(data, parent_children_map,
show_zero_values=filters.get("show_zero_values"))
data = filter_out_zero_value_rows(data, parent_children_map, show_zero_values=filters.get("show_zero_values"))
return data
@@ -175,33 +174,11 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters,
d["closing_debit"] = d["opening_debit"] + d["debit"]
d["closing_credit"] = d["opening_credit"] + d["credit"]
total_row["debit"] += d["debit"]
total_row["credit"] += d["credit"]
if d["root_type"] == "Asset" or d["root_type"] == "Equity" or d["root_type"] == "Expense":
d["opening_debit"] -= d["opening_credit"]
d["closing_debit"] -= d["closing_credit"]
prepare_opening_closing(d)
# For opening
check_opening_closing_has_negative_value(d, "opening_debit", "opening_credit")
# For closing
check_opening_closing_has_negative_value(d, "closing_debit", "closing_credit")
if d["root_type"] == "Liability" or d["root_type"] == "Income":
d["opening_credit"] -= d["opening_debit"]
d["closing_credit"] -= d["closing_debit"]
# For opening
check_opening_closing_has_negative_value(d, "opening_credit", "opening_debit")
# For closing
check_opening_closing_has_negative_value(d, "closing_credit", "closing_debit")
total_row["opening_debit"] += d["opening_debit"]
total_row["closing_debit"] += d["closing_debit"]
total_row["opening_credit"] += d["opening_credit"]
total_row["closing_credit"] += d["closing_credit"]
for field in value_fields:
total_row[field] += d[field]
return total_row
@@ -215,6 +192,10 @@ def prepare_data(accounts, filters, total_row, parent_children_map, company_curr
data = []
for d in accounts:
# Prepare opening closing for group account
if parent_children_map.get(d.account):
prepare_opening_closing(d)
has_value = False
row = {
"account": d.name,
@@ -301,11 +282,16 @@ def get_columns():
}
]
def check_opening_closing_has_negative_value(d, dr_or_cr, switch_to_column):
# If opening debit has negetive value then move it to opening credit and vice versa.
def prepare_opening_closing(row):
dr_or_cr = "debit" if row["root_type"] in ["Asset", "Equity", "Expense"] else "credit"
reverse_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit"
if d[dr_or_cr] < 0:
d[switch_to_column] = abs(d[dr_or_cr])
d[dr_or_cr] = 0.0
else:
d[switch_to_column] = 0.0
for col_type in ["opening", "closing"]:
valid_col = col_type + "_" + dr_or_cr
reverse_col = col_type + "_" + reverse_dr_or_cr
row[valid_col] -= row[reverse_col]
if row[valid_col] < 0:
row[reverse_col] = abs(row[valid_col])
row[valid_col] = 0.0
else:
row[reverse_col] = 0.0

View File

@@ -18,14 +18,17 @@ def execute(filters=None):
return columns, data
def get_data(filters, show_party_name):
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
if filters.get('party_type') == 'Student':
party_name_field = 'first_name'
elif filters.get('party_type') == 'Shareholder':
party_name_field = 'title'
else:
party_name_field = 'name'
party_filters = {"name": filters.get("party")} if filters.get("party") else {}
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
filters = party_filters, order_by="name")
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
opening_balances = get_opening_balances(filters)
@@ -70,7 +73,7 @@ def get_data(filters, show_party_name):
# totals
for col in total_row:
total_row[col] += row.get(col)
row.update({
"currency": company_currency
})
@@ -78,7 +81,7 @@ def get_data(filters, show_party_name):
has_value = False
if (opening_debit or opening_credit or debit or credit or closing_debit or closing_credit):
has_value =True
if cint(filters.show_zero_values) or has_value:
data.append(row)
@@ -94,9 +97,9 @@ def get_data(filters, show_party_name):
def get_opening_balances(filters):
gle = frappe.db.sql("""
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
from `tabGL Entry`
where company=%(company)s
where company=%(company)s
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
group by party""", {
@@ -114,11 +117,11 @@ def get_opening_balances(filters):
def get_balances_within_period(filters):
gle = frappe.db.sql("""
select party, sum(debit) as debit, sum(credit) as credit
select party, sum(debit) as debit, sum(credit) as credit
from `tabGL Entry`
where company=%(company)s
where company=%(company)s
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
and ifnull(is_opening, 'No') = 'No'
group by party""", {
"company": filters.company,

View File

@@ -138,7 +138,7 @@ def refresh_scorecards():
# Check to see if any new scorecard periods are created
if make_all_scorecards(sc.name) > 0:
# Save the scorecard to update the score and standings
sc.save()
frappe.get_doc('Supplier Scorecard', sc.name).save()
@frappe.whitelist()

View File

@@ -375,9 +375,10 @@ class AccountsController(TransactionBase):
return gl_dict
def validate_qty_is_not_zero(self):
for item in self.items:
if not item.qty:
frappe.throw(_("Item quantity can not be zero"))
if self.doctype != "Purchase Receipt":
for item in self.items:
if not item.qty:
frappe.throw(_("Item quantity can not be zero"))
def validate_account_currency(self, account, account_currency=None):
valid_currency = [self.company_currency]
@@ -1097,6 +1098,8 @@ def get_supplier_block_status(party_name):
@frappe.whitelist()
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
data = json.loads(trans_items)
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
for d in data:
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
@@ -1114,8 +1117,26 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
else:
child_item.rate = flt(d.get("rate"))
if flt(child_item.price_list_rate):
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0, \
child_item.precision("discount_percentage"))
if flt(child_item.rate) > flt(child_item.price_list_rate):
# if rate is greater than price_list_rate, set margin
# or set discount
child_item.discount_percentage = 0
if parent_doctype in sales_doctypes:
child_item.margin_type = "Amount"
child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
child_item.precision("margin_rate_or_amount"))
child_item.rate_with_margin = child_item.rate
else:
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
child_item.precision("discount_percentage"))
child_item.discount_amount = flt(
child_item.price_list_rate) - flt(child_item.rate)
if parent_doctype in sales_doctypes:
child_item.margin_type = ""
child_item.margin_rate_or_amount = 0
child_item.rate_with_margin = 0
child_item.flags.ignore_validate_update_after_submit = True
child_item.save()

View File

@@ -515,10 +515,15 @@ class BuyingController(StockController):
for d in self.get('supplied_items'):
# negative quantity is passed, as raw material qty has to be decreased
# when PR is submitted and it has to be increased when PR is cancelled
incoming_rate = 0
if self.is_return and self.return_against and self.docstatus==1:
incoming_rate = self.get_incoming_rate_for_sales_return(d.rm_item_code, self.return_against)
sl_entries.append(self.get_sl_entries(d, {
"item_code": d.rm_item_code,
"warehouse": self.supplier_warehouse,
"actual_qty": -1*flt(d.consumed_qty),
"incoming_rate": incoming_rate
}))
def on_submit(self):

View File

@@ -292,6 +292,7 @@ def copy_attributes_to_variant(item, variant):
if not variant.description:
variant.description = ""
else:
if item.variant_based_on=='Item Attribute':
if variant.attributes:
attributes_description = item.description + " "
@@ -299,7 +300,7 @@ def copy_attributes_to_variant(item, variant):
attributes_description += "<div>" + d.attribute + ": " + cstr(d.attribute_value) + "</div>"
if attributes_description not in variant.description:
variant.description += attributes_description
variant.description = attributes_description
def make_variant_item_code(template_item_code, template_item_name, variant):
"""Uses template's item code and abbreviations to make variant's item code"""

View File

@@ -152,6 +152,24 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
#Get searchfields from meta and use in Item Link field query
meta = frappe.get_meta("Item", cached=True)
searchfields = meta.get_search_fields()
if "description" in searchfields:
searchfields.remove("description")
columns = ''
extra_searchfields = [field for field in searchfields
if field not in ["name", "item_group", "description"]]
if extra_searchfields:
columns = ", " + ", ".join(extra_searchfields)
searchfields = searchfields + [field for field in[searchfield or "name", "item_code", "item_group", "item_name"]
if not field in searchfields]
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
description_cond = ''
if frappe.db.count('Item', cache=True) < 50000:
# scan description only if items are less than 50000
@@ -162,17 +180,14 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
tabItem.item_group,
if(length(tabItem.description) > 40, \
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
concat(substr(tabItem.description, 1, 40), "..."), description) as description
{columns}
from tabItem
where tabItem.docstatus < 2
and tabItem.has_variants=0
and tabItem.disabled=0
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
and (tabItem.`{key}` LIKE %(txt)s
or tabItem.item_code LIKE %(txt)s
or tabItem.item_group LIKE %(txt)s
or tabItem.item_name LIKE %(txt)s
or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
{description_cond})
{fcond} {mcond}
order by
@@ -182,6 +197,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
name, item_name
limit %(start)s, %(page_len)s """.format(
key=searchfield,
columns=columns,
scond=searchfields,
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
mcond=get_match_cond(doctype).replace('%', '%%'),
description_cond = description_cond),
@@ -280,22 +297,32 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
"page_len": page_len
}
having_clause = "having sum(sle.actual_qty) > 0"
if filters.get("is_return"):
having_clause = ""
if args.get('warehouse'):
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom, concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
from `tabStock Ledger Entry` sle
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
where
batch.disabled = 0
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{0}
{match_conditions}
group by batch_no having sum(sle.actual_qty) > 0
order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom,
concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
from `tabStock Ledger Entry` sle
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
where
batch.disabled = 0
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
or batch.expiry_date like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{cond}
{match_conditions}
group by batch_no {having_clause}
order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(
cond=cond,
match_conditions=get_match_cond(doctype),
having_clause = having_clause
), args)
return batch_nos
else:
@@ -303,6 +330,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
where batch.disabled = 0
and item = %(item_code)s
and (name like %(txt)s
or expiry_date like %(txt)s
or manufacturing_date like %(txt)s)
and docstatus < 2
{0}

View File

@@ -72,7 +72,7 @@ def validate_returned_items(doc):
items_returned = False
for d in doc.get("items"):
if d.item_code and (flt(d.qty) < 0 or d.get('received_qty') < 0):
if d.item_code and (flt(d.qty) < 0 or flt(d.get('received_qty')) < 0):
if d.item_code not in valid_items:
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
.format(d.idx, d.item_code, doc.doctype, doc.return_against))

View File

@@ -306,8 +306,9 @@ class SellingController(StockController):
if flt(d.conversion_factor)==0.0:
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
return_rate = 0
if cint(self.is_return) and self.return_against and self.docstatus==1:
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
if cint(self.is_return) and self.docstatus==1:
return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
d.warehouse, self.return_against)
# On cancellation or if return entry submission, make stock ledger entry for
# target warehouse first, to update serial no values properly

View File

@@ -299,7 +299,7 @@ class StockController(AccountsController):
return serialized_items
def get_incoming_rate_for_sales_return(self, item_code, against_document):
def get_incoming_rate_for_sales_return(self, item_code, warehouse, against_document):
incoming_rate = 0.0
if against_document and item_code:
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
@@ -308,6 +308,9 @@ class StockController(AccountsController):
and item_code = %s limit 1""",
(self.doctype, against_document, item_code))
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
else:
incoming_rate = get_valuation_rate(item_code, warehouse,
self.doctype, against_document, company=self.company, currency=self.currency)
return incoming_rate

View File

@@ -305,11 +305,19 @@ class calculate_taxes_and_totals(object):
last_tax = self.doc.get("taxes")[-1]
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
for d in self.doc.get("taxes") if not d.included_in_print_rate])
diff = self.doc.total + non_inclusive_tax_amount \
- flt(last_tax.total, last_tax.precision("total"))
# If discount amount applied, deduct the discount amount
# because self.doc.total is always without discount, but last_tax.total is after discount
if self.discount_amount_applied and self.doc.discount_amount:
diff -= flt(self.doc.discount_amount)
diff = flt(diff, self.doc.precision("rounding_adjustment"))
if diff and abs(diff) <= (5.0 / 10**last_tax.precision("tax_amount")):
self.doc.rounding_adjustment = flt(flt(self.doc.rounding_adjustment) +
flt(diff), self.doc.precision("rounding_adjustment"))
self.doc.rounding_adjustment = diff
def calculate_totals(self):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \

File diff suppressed because it is too large Load Diff

View File

@@ -1468,7 +1468,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-05-17 19:03:32.740910",
"modified": "2019-10-22 11:11:32.740910",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2017-04-17 00:20:27.248275",
"modified": "2019-04-17 00:20:27.248275",
"modified_by": "Administrator",
"module": "CRM",
"name": "Campaign Efficiency",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2018-09-17 14:40:52.035394",
"modified": "2019-09-19 14:40:52.035394",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Conversion Time",

View File

@@ -67,7 +67,7 @@ def get_communication_details(filters):
communication_count = None
communication_list = []
opportunities = frappe.db.get_values('Opportunity', {'opportunity_from': 'Lead'},\
['name', 'customer_name', 'lead', 'contact_email'], as_dict=1)
['name', 'customer_name', 'contact_email'], as_dict=1)
for d in opportunities:
invoice = frappe.db.sql('''

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Shishuvan Secondary School",
"modified": "2018-02-08 15:11:35.339434",
"modified": "2019-02-08 15:11:35.339434",
"modified_by": "Administrator",
"module": "Education",
"name": "Final Assessment Grades",

File diff suppressed because it is too large Load Diff

View File

@@ -233,7 +233,6 @@ scheduler_events = {
],
"daily": [
"erpnext.stock.reorder_item.reorder_item",
"erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.support.doctype.issue.issue.auto_close_tickets",
"erpnext.crm.doctype.opportunity.opportunity.auto_close_opportunity",
"erpnext.controllers.accounts_controller.update_invoice_status",
@@ -252,6 +251,7 @@ scheduler_events = {
"erpnext.projects.doctype.project.project.send_project_status_email_to_users"
],
"daily_long": [
"erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
],
"monthly_long": [

View File

@@ -157,10 +157,11 @@ class Employee(NestedSet):
def validate_status(self):
if self.status == 'Left':
reports_to = frappe.db.get_all('Employee',
filters={'reports_to': self.name}
filters={'reports_to': self.name, 'status': "Active"},
fields = ['name','employee_name']
)
if reports_to:
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name, label=employee.employee_name) for employee in reports_to]
throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee:&nbsp;")
+ ', '.join(link_to_employees), EmployeeLeftValidationError)
if not self.relieving_date:

View File

@@ -7,6 +7,14 @@ frappe.ui.form.on('Employee Onboarding', {
frm.add_fetch("employee_onboarding_template", "department", "department");
frm.add_fetch("employee_onboarding_template", "designation", "designation");
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
frm.set_query('job_offer', function () {
return {
filters: {
'job_applicant': frm.doc.job_applicant
}
};
});
},
refresh: function(frm) {

View File

@@ -13,6 +13,7 @@ class Loan(AccountsController):
def validate(self):
validate_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, self.repayment_periods)
self.set_missing_fields()
self.validate_loan_application()
self.make_repayment_schedule()
self.set_repayment_period()
self.calculate_totals()
@@ -33,6 +34,13 @@ class Loan(AccountsController):
if self.status == "Repaid/Closed":
self.total_amount_paid = self.total_payment
def validate_loan_application(self):
if self.loan_application:
loan = frappe.db.get_value("Loan", {"loan_application": self.loan_application}, "name")
if loan and loan != self.name:
frappe.throw(_("Loan {0} already created for Loan Application {1}").format(frappe.bold(loan),
frappe.bold(self.loan_application)))
def make_jv_entry(self):
self.check_permission('write')
@@ -116,6 +124,7 @@ def update_disbursement_status(doc):
""", (doc.payment_account, doc.name), as_dict=1)[0]
disbursement_date = None
status = ''
if not disbursement or disbursement.disbursed_amount == 0:
status = "Sanctioned"
elif disbursement.disbursed_amount == doc.loan_amount:

View File

@@ -23,20 +23,25 @@ frappe.ui.form.on('Loan Application', {
},
add_toolbar_buttons: function(frm) {
if (frm.doc.status == "Approved") {
frm.add_custom_button(__('Create Loan'), function() {
frappe.call({
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
args: {
"source_name": frm.doc.name
},
callback: function(r) {
if(!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
}
}
});
}).addClass("btn-primary");
// show create loan button if loan not created against loan aplication
frappe.db.get_value("Loan", {"loan_application": frm.doc.name}, "name", (r) => {
if (!r) {
frm.add_custom_button(__('Create Loan'), function() {
frappe.call({
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
args: {
"source_name": frm.doc.name
},
callback: function(r) {
if(!r.exc) {
var doc = frappe.model.sync(r.message);
frappe.set_route("Form", r.message.doctype, r.message.name);
}
}
});
}).addClass("btn-primary");
}
});
}
}
});

View File

@@ -117,7 +117,7 @@ frappe.ui.form.on("BOM", {
args: {
update_parent: true,
from_child_bom:false,
save: false
save: frm.doc.docstatus === 1 ? true : false
},
callback: function(r) {
refresh_field("items");

View File

@@ -34,12 +34,15 @@ class BOM(WebsiteGenerator):
# name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1
# split by item
names = [name.split(self.item)[-1][1:] for name in names]
names = [name.split(self.item, 1) for name in names]
names = [d[-1][1:] for d in filter(lambda x: len(x) > 1 and x[-1], names)]
# split by (-) if cancelled
names = [cint(name.split('-')[-1]) for name in names]
idx = max(names) + 1
if names:
names = [cint(name.split('-')[-1]) for name in names]
idx = max(names) + 1
else:
idx = 1
else:
idx = 1

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -14,10 +15,12 @@
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
@@ -41,14 +44,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_name",
"fieldtype": "Data",
"hidden": 0,
@@ -72,14 +78,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -103,14 +112,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -132,14 +144,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "quantity",
"fieldtype": "Float",
"hidden": 0,
@@ -162,14 +177,51 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "UOM",
"length": 0,
"no_copy": 0,
"options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "actual_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -192,14 +244,86 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "300px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "min_order_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -222,14 +346,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"hidden": 0,
@@ -252,14 +379,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_order",
"fieldtype": "Link",
"hidden": 0,
@@ -283,14 +413,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "requested_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -313,6 +446,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@@ -326,7 +460,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-02-15 13:08:30.535963",
"modified": "2019-11-08 14:59:58.805613",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Material Request Plan Item",
@@ -340,5 +474,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
"track_seen": 0,
"track_views": 0
}

View File

@@ -122,6 +122,8 @@ frappe.ui.form.on('Production Plan', {
item.quantity = d.quantity;
item.sales_order = d.sales_order;
item.warehouse = d.warehouse;
item.description = d.description;
item.uom = d.uom;
});
}
refresh_field('mr_items');

View File

@@ -472,7 +472,9 @@ def get_material_request_items(row, sales_order, company, ignore_existing_ordere
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
'actual_qty': actual_qty,
'min_order_qty': row['min_order_qty'],
'sales_order': sales_order
'sales_order': sales_order,
'description': row.get("description"),
'uom': row.get("purchase_uom") or row.get("stock_uom")
}
def get_sales_orders(self):

View File

@@ -318,7 +318,7 @@ frappe.ui.form.on("Work Order", {
},
project: function(frm) {
if(!erpnext.in_production_item_onchange) {
if(!erpnext.in_production_item_onchange && !frm.doc.bom_no) {
frm.trigger("production_item");
}
},
@@ -371,6 +371,11 @@ frappe.ui.form.on("Work Order", {
}
});
}
},
additional_operating_cost: function(frm) {
erpnext.work_order.calculate_cost(frm.doc);
erpnext.work_order.calculate_total_cost(frm);
}
});
@@ -507,8 +512,7 @@ erpnext.work_order = {
},
calculate_total_cost: function(frm) {
var variable_cost = frm.doc.actual_operating_cost ?
flt(frm.doc.actual_operating_cost) : flt(frm.doc.planned_operating_cost)
let variable_cost = flt(frm.doc.actual_operating_cost) || flt(frm.doc.planned_operating_cost);
frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost))
},

View File

@@ -204,6 +204,8 @@ class WorkOrder(Document):
self.meta.get_label(fieldname), qty, completed_qty, self.name), StockOverProductionError)
self.db_set(fieldname, qty)
from erpnext.selling.doctype.sales_order.sales_order import update_produced_qty_in_so_item
update_produced_qty_in_so_item(self.sales_order_item)
if self.production_plan:
self.update_production_plan_status()

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-05-28 16:22:24.040106",
"modified": "2018-06-28 16:22:24.040106",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Variance Report",

View File

@@ -606,3 +606,5 @@ erpnext.patches.v11_1.set_missing_opportunity_from
erpnext.patches.v11_1.set_quotation_status
erpnext.patches.v11_1.update_default_supplier_in_item_defaults
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
erpnext.patches.v11_1.set_produced_qty_field_in_sales_order_for_work_order
erpnext.patches.v11_1.set_payment_entry_status

View File

@@ -0,0 +1,9 @@
import frappe
def execute():
frappe.reload_doctype("Payment Entry")
frappe.db.sql("""update `tabPayment Entry` set status = CASE
WHEN docstatus = 1 THEN 'Submitted'
WHEN docstatus = 2 THEN 'Cancelled'
ELSE 'Draft'
END;""")

View File

@@ -0,0 +1,9 @@
import frappe
from erpnext.selling.doctype.sales_order.sales_order import update_produced_qty_in_so_item
def execute():
frappe.reload_doctype('Sales Order Item')
frappe.reload_doctype('Sales Order')
sales_order_items = frappe.db.get_all('Sales Order Item', ['name'])
for so_item in sales_order_items:
update_produced_qty_in_so_item(so_item.get('name'))

View File

@@ -200,7 +200,11 @@ class Project(Document):
frappe.db.set_value("Sales Order", self.sales_order, "project", self.name)
def update_percent_complete(self, from_validate=False):
if not self.tasks: return
if not self.tasks:
if self.status == "Completed" :
self.percent_complete = 100
return
total = frappe.db.sql("""select count(name) from tabTask where project=%s""", self.name)[0][0]
if not total and self.percent_complete:
self.percent_complete = 0

View File

@@ -713,7 +713,7 @@
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "depends_on_tasks",
"fieldtype": "Data",
"fieldtype": "Long Text",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1433,4 +1433,4 @@
"track_changes": 0,
"track_seen": 1,
"track_views": 0
}
}

View File

@@ -7,7 +7,7 @@ import json
import frappe
from frappe import _, throw
from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate
from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today
from frappe.utils.nestedset import NestedSet
@@ -47,8 +47,8 @@ class Task(NestedSet):
def validate_status(self):
if self.status!=self.get_db_value("status") and self.status == "Closed":
for d in self.depends_on:
if frappe.db.get_value("Task", d.task, "status") != "Closed":
frappe.throw(_("Cannot close task as its dependant task {0} is not closed.").format(d.task))
if frappe.db.get_value("Task", d.task, "status") not in ("Closed", "Cancelled"):
frappe.throw(_("Cannot close task as its dependant task {0} is not closed/cancelled.").format(d.task))
from frappe.desk.form.assign_to import clear
clear(self.doctype, self.name)
@@ -201,6 +201,9 @@ def set_multiple_status(names, status):
def set_tasks_as_overdue():
tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Closed']]})
for task in tasks:
if frappe.db.get_value("Task", task.name, "status") in 'Pending Review':
if getdate(frappe.db.get_value("Task", task.name, "review_date")) < getdate(today()):
continue
frappe.get_doc("Task", task.name).update_status()
@frappe.whitelist()

View File

@@ -191,6 +191,9 @@ class Timesheet(Document):
}, as_dict=True)
# check internal overlap
for time_log in self.time_logs:
if not (time_log.from_time and time_log.to_time
and args.from_time and args.to_time): continue
if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \
args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
(args.to_time > time_log.from_time and args.to_time < time_log.to_time) or

View File

@@ -387,9 +387,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
var diff = me.frm.doc.total + non_inclusive_tax_amount
- flt(last_tax.total, precision("grand_total"));
if(me.discount_amount_applied && me.frm.doc.discount_amount) {
diff -= flt(me.frm.doc.discount_amount);
}
diff = flt(diff, precision("rounding_adjustment"));
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
this.frm.doc.rounding_adjustment = flt(flt(this.frm.doc.rounding_adjustment) + diff,
precision("rounding_adjustment"));
me.frm.doc.rounding_adjustment = diff;
}
}
}

View File

@@ -853,15 +853,19 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
},
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
if(doc.doctype != 'Material Request' && frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
item.total_weight = flt(item.stock_qty * item.weight_per_unit);
refresh_field("stock_qty", item.name, item.parentfield);
refresh_field("total_weight", item.name, item.parentfield);
this.toggle_conversion_factor(item);
this.calculate_net_weight();
if(doc.doctype != "Material Request") {
item.total_weight = flt(item.stock_qty * item.weight_per_unit);
refresh_field("total_weight", item.name, item.parentfield);
this.calculate_net_weight();
}
if (!dont_fetch_price_list_rate &&
frappe.meta.has_field(doc.doctype, "price_list_currency")) {
this.apply_price_list(item, true);
@@ -1422,6 +1426,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
'item_code': item.item_code,
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
}
if (doc.is_return) {
filters["is_return"] = 1;
}
if (item.warehouse) filters["warehouse"] = item.warehouse;
return {

View File

@@ -2,6 +2,7 @@ frappe.provide('frappe.ui.form');
frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
init: function(doctype, after_insert) {
this.skip_redirect_on_error = true;
this._super(doctype, after_insert);
},
@@ -37,8 +38,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("Address Line 1"),
fieldname: "address_line1",
fieldtype: "Data",
reqd: 1
fieldtype: "Data"
},
{
label: __("Address Line 2"),
@@ -56,8 +56,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("City"),
fieldname: "city",
fieldtype: "Data",
reqd: 1,
fieldtype: "Data"
},
{
label: __("State"),
@@ -68,8 +67,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
options: "Country",
reqd: 1
options: "Country"
},
{
label: __("Customer POS Id"),

View File

@@ -60,8 +60,8 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
frappe.throw(_("Invalid {0}! The check digit validation has failed. " +
"Please ensure you've typed the {0} correctly.".format(label)))
frappe.throw(_("""Invalid {0}! The check digit validation has failed.
Please ensure you've typed the {0} correctly.""".format(label)))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):

View File

@@ -19,7 +19,7 @@
{%- endmacro %}
{%- macro render_discount_or_margin(item) -%}
{%- if item.discount_percentage > 0.0 or item.margin_type %}
{%- if (item.discount_percentage and item.discount_percentage > 0.0) or item.margin_type %}
<ScontoMaggiorazione>
{%- if item.discount_percentage > 0.0 %}
<Tipo>SC</Tipo>

View File

@@ -153,8 +153,7 @@ def get_invoice_summary(items, taxes):
tax_rate=tax.rate,
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount,
taxable_amount=(reference_row.tax_amount if tax.charge_type == 'On Previous Row Amount'
else reference_row.total),
taxable_amount=reference_row.tax_amount,
item_tax_rate={tax.account_head: tax.rate},
charges=True,
type="Actual",
@@ -189,6 +188,10 @@ def get_invoice_summary(items, taxes):
summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason
summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law
if summary_data.get("0.0") and tax.charge_type in ["On Previous Row Total",
"On Previous Row Amount"]:
summary_data[key]["taxable_amount"] = tax.total
if summary_data == {}: #Implies that Zero VAT has not been set on any item.
summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total,
"tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law})

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Standard",
"modified": "2018-04-26 12:59:38.603649",
"modified": "2019-04-26 12:59:38.603649",
"modified_by": "Administrator",
"module": "Regional",
"name": "HSN-wise-summary of outward supplies",

View File

@@ -340,6 +340,16 @@ def make_contact(args, is_primary_contact=1):
return contact
def make_address(args, is_primary_address=1):
reqd_fields = []
for field in ['city', 'country']:
if not args.get(field):
reqd_fields.append( '<li>' + field.title() + '</li>')
if reqd_fields:
msg = _("Following fields are mandatory to create address:")
frappe.throw("{0} <br><br> <ul>{1}</ul>".format(msg, '\n'.join(reqd_fields)),
title = _("Missing Values Required"))
address = frappe.get_doc({
'doctype': 'Address',
'address_title': args.get('name'),

View File

@@ -142,7 +142,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
// delivery note
if(flt(doc.per_delivered, 6) < 100 && allow_delivery) {
this.frm.add_custom_button(__('Delivery'),
this.frm.add_custom_button(__('Delivery Note'),
function() { me.make_delivery_note_based_on_delivery_date(); }, __("Make"));
if(["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1){

View File

@@ -645,12 +645,15 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
if source_parent.project:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")
if not target.cost_center and target.item_code:
if target.item_code:
item = get_item_defaults(target.item_code, source_parent.company)
item_group = get_item_group_defaults(target.item_code, source_parent.company)
target.cost_center = item.get("selling_cost_center") \
cost_center = item.get("selling_cost_center") \
or item_group.get("selling_cost_center")
if cost_center:
target.cost_center = cost_center
doclist = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
"doctype": "Sales Invoice",
@@ -973,3 +976,15 @@ def make_raw_material_request(items, company, sales_order, project=None):
material_request.run_method("set_missing_values")
material_request.submit()
return material_request
def update_produced_qty_in_so_item(sales_order_item):
#for multiple work orders against same sales order item
linked_wo_with_so_item = frappe.db.get_all('Work Order', ['produced_qty'], {
'sales_order_item': sales_order_item,
'docstatus': 1
})
if len(linked_wo_with_so_item) > 0:
total_produced_qty = 0
for wo in linked_wo_with_so_item:
total_produced_qty += flt(wo.get('produced_qty'))
frappe.db.set_value('Sales Order Item', sales_order_item, 'produced_qty', total_produced_qty)

View File

@@ -21,6 +21,7 @@
"bold": 1,
"collapsible": 0,
"columns": 3,
"fetch_if_empty": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
@@ -57,6 +58,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_item_code",
"fieldtype": "Data",
"hidden": 1,
@@ -88,6 +90,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ensure_delivery_based_on_produced_serial_no",
"fieldtype": "Check",
"hidden": 0,
@@ -120,6 +123,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
@@ -150,6 +154,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_name",
"fieldtype": "Data",
"hidden": 0,
@@ -185,6 +190,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
@@ -217,6 +223,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -252,6 +259,7 @@
"bold": 0,
"collapsible": 0,
"columns": 2,
"fetch_if_empty": 0,
"fieldname": "delivery_date",
"fieldtype": "Date",
"hidden": 0,
@@ -284,6 +292,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_7",
"fieldtype": "Column Break",
"hidden": 0,
@@ -315,6 +324,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
@@ -347,6 +357,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "image_view",
"fieldtype": "Image",
"hidden": 0,
@@ -380,6 +391,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "quantity_and_rate",
"fieldtype": "Section Break",
"hidden": 0,
@@ -411,6 +423,7 @@
"bold": 0,
"collapsible": 0,
"columns": 1,
"fetch_if_empty": 0,
"fieldname": "qty",
"fieldtype": "Float",
"hidden": 0,
@@ -446,6 +459,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "stock_uom",
"fieldtype": "Link",
"hidden": 0,
@@ -482,6 +496,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break2",
"fieldtype": "Column Break",
"hidden": 0,
@@ -512,6 +527,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "uom",
"fieldtype": "Link",
"hidden": 0,
@@ -545,6 +561,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "conversion_factor",
"fieldtype": "Float",
"hidden": 0,
@@ -577,6 +594,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -609,6 +627,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_16",
"fieldtype": "Section Break",
"hidden": 0,
@@ -640,6 +659,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "price_list_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -676,6 +696,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_price_list_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -712,6 +733,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "discount_and_margin",
"fieldtype": "Section Break",
"hidden": 0,
@@ -745,6 +767,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "price_list_rate",
"fetch_if_empty": 0,
"fieldname": "margin_type",
"fieldtype": "Select",
"hidden": 0,
@@ -779,6 +802,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.margin_type && doc.price_list_rate",
"fetch_if_empty": 0,
"fieldname": "margin_rate_or_amount",
"fieldtype": "Float",
"hidden": 0,
@@ -812,6 +836,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
"fetch_if_empty": 0,
"fieldname": "rate_with_margin",
"fieldtype": "Currency",
"hidden": 0,
@@ -845,6 +870,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_19",
"fieldtype": "Column Break",
"hidden": 0,
@@ -877,6 +903,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "price_list_rate",
"fetch_if_empty": 0,
"fieldname": "discount_percentage",
"fieldtype": "Percent",
"hidden": 0,
@@ -913,6 +940,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "discount_percentage",
"fetch_if_empty": 0,
"fieldname": "discount_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -947,6 +975,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
"fetch_if_empty": 0,
"fieldname": "base_rate_with_margin",
"fieldtype": "Currency",
"hidden": 0,
@@ -980,6 +1009,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_simple1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1012,6 +1042,7 @@
"collapsible": 0,
"columns": 2,
"depends_on": "eval: doc.type != \"\"",
"fetch_if_empty": 0,
"fieldname": "rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1048,6 +1079,7 @@
"bold": 0,
"collapsible": 0,
"columns": 2,
"fetch_if_empty": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -1085,6 +1117,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1115,6 +1148,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1151,6 +1185,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -1187,6 +1222,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "pricing_rule",
"fieldtype": "Link",
"hidden": 0,
@@ -1219,6 +1255,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_24",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1250,6 +1287,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "net_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1283,6 +1321,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "net_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -1316,6 +1355,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_27",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1347,6 +1387,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_net_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1380,6 +1421,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "base_net_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -1414,6 +1456,7 @@
"collapsible": 1,
"collapsible_depends_on": "eval:doc.delivered_by_supplier==1||doc.supplier",
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "drop_ship_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1446,6 +1489,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "delivered_by_supplier",
"fieldtype": "Check",
"hidden": 0,
@@ -1478,6 +1522,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
@@ -1511,6 +1556,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_weight_details",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1543,6 +1589,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "weight_per_unit",
"fieldtype": "Float",
"hidden": 0,
@@ -1575,6 +1622,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_weight",
"fieldtype": "Float",
"hidden": 0,
@@ -1607,6 +1655,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_21",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1638,6 +1687,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "weight_uom",
"fieldtype": "Link",
"hidden": 0,
@@ -1671,6 +1721,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "warehouse_and_reference",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1703,6 +1754,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.delivered_by_supplier!=1",
"fetch_if_empty": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -1740,6 +1792,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.delivered_by_supplier!=1",
"fetch_if_empty": 0,
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
@@ -1773,6 +1826,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "prevdoc_docname",
"fieldtype": "Link",
"hidden": 0,
@@ -1807,6 +1861,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "brand",
"fieldtype": "Link",
"hidden": 1,
@@ -1842,6 +1897,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "item_group",
"fieldtype": "Link",
"hidden": 1,
@@ -1876,6 +1932,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "billed_amt",
"fieldtype": "Currency",
"hidden": 0,
@@ -1908,6 +1965,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "valuation_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1941,6 +1999,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "gross_profit",
"fieldtype": "Currency",
"hidden": 0,
@@ -1974,6 +2033,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "blanket_order",
"fieldtype": "Link",
"hidden": 0,
@@ -2007,6 +2067,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "blanket_order_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -2039,6 +2100,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "page_break",
"fieldtype": "Check",
"hidden": 0,
@@ -2072,6 +2134,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "col_break4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2102,6 +2165,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "projected_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2137,6 +2201,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "actual_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2170,6 +2235,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ordered_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2202,6 +2268,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "delivered_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2237,6 +2304,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "work_order_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2270,6 +2338,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "returned_qty",
"fetch_if_empty": 0,
"fieldname": "returned_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -2302,6 +2371,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_63",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2334,6 +2404,7 @@
"collapsible": 0,
"columns": 0,
"description": "For Production",
"fetch_if_empty": 0,
"fieldname": "planned_qty",
"fieldtype": "Float",
"hidden": 1,
@@ -2370,9 +2441,10 @@
"collapsible": 0,
"columns": 0,
"description": "For Production",
"fetch_if_empty": 0,
"fieldname": "produced_qty",
"fieldtype": "Float",
"hidden": 1,
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
@@ -2405,6 +2477,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_tax_rate",
"fieldtype": "Code",
"hidden": 1,
@@ -2439,6 +2512,7 @@
"collapsible": 0,
"columns": 0,
"description": "Used for Production Plan",
"fetch_if_empty": 0,
"fieldname": "transaction_date",
"fieldtype": "Date",
"hidden": 1,
@@ -2477,8 +2551,8 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
"modified": "2019-02-18 18:53:23.425126",
"modified_by": "Administrator",
"modified": "2019-09-30 16:58:52.524894",
"modified_by": "ruchamahabal2@gmail.com",
"module": "Selling",
"name": "Sales Order Item",
"owner": "Administrator",

View File

@@ -7,7 +7,7 @@ from frappe.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
iwq_map = get_item_warehouse_quantity_map()
item_map = get_item_details()
@@ -15,22 +15,23 @@ def execute(filters=None):
for sbom, warehouse in iwq_map.items():
total = 0
total_qty = 0
for wh, item_qty in warehouse.items():
total += 1
row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
item_map.get(sbom).stock_uom, wh]
available_qty = item_qty
total_qty += flt(available_qty)
row += [available_qty]
if available_qty:
data.append(row)
if (total == len(warehouse)):
row = ["", "", "Total", "", "", total_qty]
if item_map.get(sbom):
row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
item_map.get(sbom).stock_uom, wh]
available_qty = item_qty
total_qty += flt(available_qty)
row += [available_qty]
if available_qty:
data.append(row)
if (total == len(warehouse)):
row = ["", "", "Total", "", "", total_qty]
data.append(row)
return columns, data
def get_columns():
columns = ["Item Code:Link/Item:100", "Item Name::100", "Description::120", \
"UOM:Link/UOM:80", "Warehouse:Link/Warehouse:100", "Quantity::100"]

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Delta9",
"modified": "2019-06-12 03:25:36.263179",
"modified": "2019-06-14 03:25:36.263179",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer-wise Item Price",

View File

@@ -80,10 +80,14 @@ frappe.query_reports["Sales Analytics"] = {
var tree_type = frappe.query_report.filters[0].value;
if(tree_type == "Customer" || tree_type == "Item") {
if(tree_type == "Customer") {
row_values = data.slice(4,length-1).map(function (column) {
return column.content;
})
} else if (tree_type == "Item") {
row_values = data.slice(5,length-1).map(function (column) {
return column.content;
})
}
else {
row_values = data.slice(3,length-1).map(function (column) {

View File

@@ -114,7 +114,7 @@ class Analytics(object):
if self.filters["value_quantity"] == 'Value':
value_field = 'base_amount'
else:
value_field = 'qty'
value_field = 'stock_qty'
self.entries = frappe.db.sql("""
select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
@@ -301,8 +301,10 @@ class Analytics(object):
def get_chart_data(self):
length = len(self.columns)
if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
labels = [d.get("label") for d in self.columns[2:length-1]]
if self.filters.tree_type in ["Customer", "Supplier"]:
labels = [d.get("label") for d in self.columns[2:length - 1]]
elif self.filters.tree_type == "Item":
labels = [d.get("label") for d in self.columns[3:length - 1]]
else:
labels = [d.get("label") for d in self.columns[1:length-1]]
self.chart = {

View File

@@ -284,7 +284,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
child: item,
args: {
"batch_no": item.batch_no,
"stock_qty": item.stock_qty,
"stock_qty": item.stock_qty || item.qty, //if stock_qty field is not available, fetch qty (in case of Packed Items table)
"warehouse": item.warehouse,
"item_code": item.item_code,
"has_serial_no": has_serial_no

View File

@@ -109,7 +109,7 @@ def get_product_list_for_group(product_group=None, start=0, limit=10, search=Non
or I.name like %(search)s)"""
search = "%" + cstr(search) + "%"
query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (start, limit)
query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
data = frappe.db.sql(query, {"product_group": product_group,"search": search, "today": nowdate()}, as_dict=1)
data = adjust_qty_for_expired_items(data)

View File

@@ -66,6 +66,7 @@ def place_order():
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
sales_order.payment_schedule = []
if not cart_settings.allow_items_not_in_stock:
for item in sales_order.get("items"):
@@ -454,9 +455,8 @@ def get_applicable_shipping_rules(party=None, quotation=None):
shipping_rules = get_shipping_rules(quotation)
if shipping_rules:
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
# we need this in sorted order as per the position of the rule in the settings page
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
return [[rule, rule] for rule in shipping_rules]
def get_shipping_rules(quotation=None, cart_settings=None):
if not quotation:

View File

@@ -6,9 +6,9 @@ frappe.listview_settings['Delivery Note'] = {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.grand_total !== 0 && flt(doc.per_billed, 2) < 100) {
} else if (flt(doc.per_billed, 2) < 100) {
return [__("To Bill"), "orange", "per_billed,<,100"];
} else if (doc.grand_total === 0 || flt(doc.per_billed, 2) == 100) {
} else if (flt(doc.per_billed, 2) == 100) {
return [__("Completed"), "green", "per_billed,=,100"];
}
},

View File

@@ -518,7 +518,7 @@ class Item(WebsiteGenerator):
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
if duplicate:
frappe.throw(_("Barcode {0} already used in Item {1}").format(
item_barcode.barcode, duplicate[0][0]), frappe.DuplicateEntryError)
item_barcode.barcode, duplicate[0][0]))
item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type
if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'):

View File

@@ -124,7 +124,7 @@ class LandedCostVoucher(Document):
# update stock & gl entries for submit state of PR
doc.docstatus = 1
doc.update_stock_ledger(via_landed_cost_voucher=True)
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.make_gl_entries()
def update_rate_in_serial_no(self, receipt_document):

View File

@@ -217,7 +217,19 @@ frappe.ui.form.on('Material Request', {
make_purchase_order: function(frm) {
frappe.prompt(
{fieldname:'default_supplier', label: __('For Default Supplier (optional)'), fieldtype: 'Link', options: 'Supplier'},
{
label: __('For Default Supplier (optional)'),
fieldname:'default_supplier',
fieldtype: 'Link',
options: 'Supplier',
description: __('Select a Supplier from the Default Supplier List of the items below.'),
get_query: () => {
return {
query: "erpnext.stock.doctype.material_request.material_request.get_default_supplier_query",
filters: {'doc': frm.doc.name}
}
}
},
(values) => {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@@ -225,7 +237,8 @@ frappe.ui.form.on('Material Request', {
args: { default_supplier: values.default_supplier },
run_link_triggers: true
});
}
},
__('Enter Supplier')
)
},

View File

@@ -371,6 +371,18 @@ def get_material_requests_based_on_supplier(supplier):
material_requests = []
return material_requests, supplier_items
def get_default_supplier_query(doctype, txt, searchfield, start, page_len, filters):
doc = frappe.get_doc("Material Request", filters.get("doc"))
item_list = []
for d in doc.items:
item_list.append(d.item_code)
return frappe.db.sql("""select default_supplier
from `tabItem Default`
where parent in ({0}) and
default_supplier IS NOT NULL
""".format(', '.join(['%s']*len(item_list))),tuple(item_list))
@frappe.whitelist()
def make_supplier_quotation(source_name, target_doc=None):
def postprocess(source, target_doc):

View File

@@ -1,5 +1,7 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,10 +13,13 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "parent_item",
"fieldtype": "Link",
"hidden": 0,
@@ -39,13 +44,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
@@ -70,13 +79,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_name",
"fieldtype": "Data",
"hidden": 0,
@@ -100,13 +113,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"hidden": 0,
@@ -128,13 +145,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -159,14 +180,18 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "300px"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
@@ -188,13 +213,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -219,13 +248,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -249,13 +282,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
@@ -277,13 +314,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "qty",
"fieldtype": "Float",
"hidden": 0,
@@ -307,13 +348,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_9",
"fieldtype": "Section Break",
"hidden": 0,
@@ -335,13 +380,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "serial_no",
"fieldtype": "Text",
"hidden": 0,
@@ -363,13 +412,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_11",
"fieldtype": "Column Break",
"hidden": 0,
@@ -391,13 +444,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "batch_no",
"fieldtype": "Link",
"hidden": 0,
@@ -420,13 +477,51 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "batch_no",
"fetch_if_empty": 0,
"fieldname": "actual_batch_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Actual Batch Quantity",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_13",
"fieldtype": "Section Break",
"hidden": 0,
@@ -448,13 +543,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "actual_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -478,13 +577,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "projected_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -508,13 +611,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_16",
"fieldtype": "Column Break",
"hidden": 0,
@@ -536,13 +643,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "uom",
"fieldtype": "Link",
"hidden": 0,
@@ -567,13 +678,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "page_break",
"fieldtype": "Check",
"hidden": 0,
@@ -597,13 +712,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "prevdoc_doctype",
"fieldtype": "Data",
"hidden": 1,
@@ -627,13 +746,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "parent_detail_docname",
"fieldtype": "Data",
"hidden": 1,
@@ -657,20 +780,21 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-20 13:27:37.569945",
"modified": "2019-11-27 11:18:18.598759",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
@@ -681,5 +805,6 @@
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 1,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View File

@@ -7,7 +7,6 @@ from __future__ import unicode_literals
import frappe, json
from frappe.utils import cstr, flt
from erpnext.stock.get_item_details import get_item_details
from frappe.model.document import Document
class PackedItem(Document):
@@ -31,8 +30,11 @@ def get_bin_qty(item, warehouse):
return det and det[0] or frappe._dict()
def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
if doc.amended_from:
old_packed_items_map = get_old_packed_item_details(doc.packed_items)
else:
old_packed_items_map = False
item = get_packing_item_details(packing_item_code, doc.company)
# check if exists
exists = 0
for d in doc.get("packed_items"):
@@ -52,11 +54,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
pi.uom = item.stock_uom
pi.qty = flt(qty)
pi.description = description
if not pi.warehouse:
if not pi.warehouse and not doc.amended_from:
pi.warehouse = (main_item_row.warehouse if ((doc.get('is_pos')
or not item.default_warehouse) and main_item_row.warehouse) else item.default_warehouse)
if not pi.batch_no:
if not pi.batch_no and not doc.amended_from:
pi.batch_no = cstr(main_item_row.get("batch_no"))
if not pi.target_warehouse:
pi.target_warehouse = main_item_row.get("target_warehouse")
@@ -64,9 +65,13 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
pi.actual_qty = flt(bin.get("actual_qty"))
pi.projected_qty = flt(bin.get("projected_qty"))
if old_packed_items_map and old_packed_items_map.get((packing_item_code, main_item_row.item_code)):
pi.batch_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].batch_no
pi.serial_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].serial_no
pi.warehouse = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].warehouse
def make_packing_list(doc):
"""make packing list for Product Bundle item"""
if doc.get("_action") and doc._action == "update_after_submit": return
parent_items = []
@@ -108,8 +113,14 @@ def get_items_from_product_bundle(args):
"qty": flt(args["quantity"]) * flt(item.qty)
})
items.append(get_item_details(args))
return items
def on_doctype_update():
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
def get_old_packed_item_details(old_packed_items):
old_packed_items_map = {}
for items in old_packed_items:
old_packed_items_map.setdefault((items.item_code ,items.parent_item), []).append(items.as_dict())
return old_packed_items_map

View File

@@ -27,6 +27,12 @@ frappe.ui.form.on("Purchase Receipt", {
}
});
frm.set_query("taxes_and_charges", function() {
return {
filters: {'company': frm.doc.company }
}
});
},
onload: function(frm) {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
@@ -105,10 +111,10 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
cur_frm.add_custom_button(__("Close"), this.close_purchase_receipt, __("Status"))
}
cur_frm.add_custom_button(__('Return'), this.make_purchase_return, __("Make"));
cur_frm.add_custom_button(__('Purchase Return'), this.make_purchase_return, __("Make"));
if(flt(this.frm.doc.per_billed) < 100) {
cur_frm.add_custom_button(__('Invoice'), this.make_purchase_invoice, __("Make"));
cur_frm.add_custom_button(__('Purchase Invoice'), this.make_purchase_invoice, __("Make"));
}
cur_frm.add_custom_button(__('Retention Stock Entry'), this.make_retention_stock_entry, __("Make"));

View File

@@ -227,7 +227,9 @@ class StockEntry(StockController):
for d in self.get("items"):
if not d.expense_account:
frappe.throw(_("Please enter Difference Account"))
frappe.throw(_("Please enter <b>Difference Account</b> or set default <b>Stock Adjustment Account</b> for company {0}")
.format(frappe.bold(self.company)))
elif self.is_opening == "Yes" and frappe.db.get_value("Account", d.expense_account, "report_type") == "Profit and Loss":
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Entry is an Opening Entry"), OpeningEntryAccountError)
@@ -346,7 +348,7 @@ class StockEntry(StockController):
elif d.t_warehouse and not d.basic_rate:
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
self.doctype, d.name, d.allow_zero_valuation_rate,
currency=erpnext.get_company_currency(self.company))
currency=erpnext.get_company_currency(self.company), company=self.company)
def set_actual_qty(self):
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))

View File

@@ -3,6 +3,15 @@
frappe.ui.form.on('Stock Settings', {
refresh: function(frm) {
let filters = function() {
return {
filters : {
is_group : 0
}
};
};
frm.set_query("default_warehouse", filters);
frm.set_query("sample_retention_warehouse", filters);
}
});

View File

@@ -30,9 +30,17 @@ class StockSettings(Document):
frappe.make_property_setter({'fieldname': name, 'property': 'hidden',
'value': 0 if self.show_barcode_field else 1})
self.validate_warehouses()
self.cant_change_valuation_method()
self.validate_clean_description_html()
def validate_warehouses(self):
warehouse_fields = ["default_warehouse", "sample_retention_warehouse"]
for field in warehouse_fields:
if frappe.db.get_value("Warehouse", self.get(field), "is_group"):
frappe.throw(_("Group Warehouses cannot be used in transactions. Please change the value of {0}") \
.format(frappe.bold(self.meta.get_field(field).label)), title =_("Incorrect Warehouse"))
def cant_change_valuation_method(self):
db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method")

View File

@@ -24,7 +24,7 @@ def execute(filters=None):
data = []
for item in items:
total_outgoing = consumed_item_map.get(item.name, 0) + delivered_item_map.get(item.name,0)
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
@@ -55,18 +55,20 @@ def get_item_info(filters):
def get_consumed_items(condition):
cn_items = frappe.db.sql("""select se_item.item_code,
sum(se_item.transfer_qty) as 'consume_qty'
from `tabStock Entry` se, `tabStock Entry Detail` se_item
where se.name = se_item.parent and se.docstatus = 1
and (ifnull(se_item.t_warehouse, '') = '' or se.purpose = 'Subcontract') %s
group by se_item.item_code""" % (condition), as_dict=1)
consumed_items = frappe.db.sql("""
select item_code, abs(sum(actual_qty)) as consumed_qty
from `tabStock Ledger Entry`
where actual_qty < 0
and voucher_type not in ('Delivery Note', 'Sales Invoice')
%s
group by item_code
""" % condition, as_dict=1)
cn_items_map = {}
for item in cn_items:
cn_items_map.setdefault(item.item_code, item.consume_qty)
consumed_items_map = {}
for item in consumed_items:
consumed_items_map.setdefault(item.item_code, item.consumed_qty)
return cn_items_map
return consumed_items_map
def get_delivered_items(condition):
dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.stock_qty) as dn_qty

View File

@@ -261,7 +261,7 @@ def validate_filters(filters):
if not (filters.get("item_code") or filters.get("warehouse")):
sle_count = flt(frappe.db.sql("""select count(name) from `tabStock Ledger Entry`""")[0][0])
if sle_count > 500000:
frappe.throw(_("Please set filter based on Item or Warehouse"))
frappe.throw(_("Please set filter based on Item or Warehouse due to a large amount of entries."))
def get_variants_attributes():
'''Return all item variant attributes.'''

View File

@@ -19,10 +19,26 @@ def execute(filters=None):
if opening_row:
data.append(opening_row)
actual_qty = stock_value = 0
for sle in sl_entries:
item_detail = item_details[sle.item_code]
sle.update(item_detail)
if filters.get("batch_no"):
actual_qty += sle.actual_qty
stock_value += sle.stock_value_difference
if sle.voucher_type == 'Stock Reconciliation':
actual_qty = sle.qty_after_transaction
stock_value = sle.stock_value
sle.update({
"qty_after_transaction": actual_qty,
"stock_value": stock_value
})
data.append(sle)
if include_uom:
@@ -67,7 +83,7 @@ def get_stock_ledger_entries(filters, items):
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project
stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project, stock_value_difference
from `tabStock Ledger Entry` sle
where company = %(company)s and
posting_date between %(from_date)s and %(to_date)s

View File

@@ -3,10 +3,10 @@
from __future__ import print_function, unicode_literals
import frappe
from frappe.utils import flt, cstr, nowdate, nowtime
from erpnext.stock.utils import update_bin
from erpnext.stock.stock_ledger import update_entries_after
from erpnext.controllers.stock_controller import update_gl_entries_after
def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
"""
@@ -18,23 +18,29 @@ def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False,
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
for d in frappe.db.sql("""select distinct item_code, warehouse from
(select item_code, warehouse from tabBin
union
select item_code, warehouse from `tabStock Ledger Entry`) a"""):
try:
repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin)
frappe.db.commit()
except:
frappe.db.rollback()
item_warehouses = frappe.db.sql("""
select distinct item_code, warehouse
from
(select item_code, warehouse from tabBin
union
select item_code, warehouse from `tabStock Ledger Entry`) a
""")
for d in item_warehouses:
try:
repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin, allow_negative_stock)
frappe.db.commit()
except:
frappe.db.rollback()
if allow_negative_stock:
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False, only_bin=False):
def repost_stock(item_code, warehouse, allow_zero_rate=False,
only_actual=False, only_bin=False, allow_negative_stock=False):
if not only_bin:
repost_actual_qty(item_code, warehouse, allow_zero_rate)
repost_actual_qty(item_code, warehouse, allow_zero_rate, allow_negative_stock)
if item_code and warehouse and not only_actual:
qty_dict = {
@@ -50,11 +56,8 @@ def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False,
update_bin_qty(item_code, warehouse, qty_dict)
def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
try:
update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
except:
pass
def repost_actual_qty(item_code, warehouse, allow_zero_rate=False, allow_negative_stock=False): update_entries_after({ "item_code": item_code, "warehouse": warehouse },
allow_zero_rate=allow_zero_rate, allow_negative_stock=allow_negative_stock)
def get_balance_qty_from_sle(item_code, warehouse):
balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
@@ -227,39 +230,14 @@ def reset_serial_no_status_and_warehouse(serial_nos=None):
except:
pass
def repost_all_stock_vouchers():
warehouses_with_account = frappe.db.sql_list("""select warehouse from tabAccount
where ifnull(account_type, '') = 'Stock' and (warehouse is not null and warehouse != '')
and is_group=0""")
def repost_gle_for_stock_transactions(posting_date=None, posting_time=None, for_warehouses=None):
frappe.db.auto_commit_on_many_writes = 1
vouchers = frappe.db.sql("""select distinct voucher_type, voucher_no
from `tabStock Ledger Entry` sle
where voucher_type != "Serial No" and sle.warehouse in (%s)
order by posting_date, posting_time, name""" %
', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
if not posting_date:
posting_date = "1900-01-01"
if not posting_time:
posting_time = "00:00"
rejected = []
i = 0
for voucher_type, voucher_no in vouchers:
i+=1
print(i, "/", len(vouchers), voucher_type, voucher_no)
try:
for dt in ["Stock Ledger Entry", "GL Entry"]:
frappe.db.sql("""delete from `tab%s` where voucher_type=%s and voucher_no=%s"""%
(dt, '%s', '%s'), (voucher_type, voucher_no))
update_gl_entries_after(posting_date, posting_time, for_warehouses=for_warehouses)
doc = frappe.get_doc(voucher_type, voucher_no)
if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]:
doc.calculate_rate_and_amount(force=1)
elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes":
doc.validate()
doc.update_stock_ledger()
doc.make_gl_entries(repost_future_gle=False)
frappe.db.commit()
except Exception:
print(frappe.get_traceback())
rejected.append([voucher_type, voucher_no])
frappe.db.rollback()
print(rejected)
frappe.db.auto_commit_on_many_writes = 0