Compare commits

...

258 Commits

Author SHA1 Message Date
mbauskar
99350db5e1 Merge branch 'staging' 2017-08-02 18:35:51 +05:30
mbauskar
478ffb9ae3 bumped to version 8.7.0 2017-08-02 19:05:51 +06:00
mbauskar
73dc35ddbf resolved merge conflicts 2017-08-02 18:24:03 +05:30
mbauskar
22a5e79b9a Merge branch 'hotfix' 2017-08-02 18:18:14 +05:30
mbauskar
4d49a7f6d1 bumped to version 8.6.6 2017-08-02 18:48:14 +06:00
Makarand Bauskar
ce436b7698 [minor] set description to '' if template description is not available (#10244) 2017-08-02 18:16:53 +05:30
rohitwaghchaure
ec9430dae7 [Fix] Default selling settings not fetched on customer quick entry form (#10243) 2017-08-02 18:16:13 +05:30
Faris Ansari
578624db1f Fix column width in GST Tax Breakup (#10230) 2017-08-02 17:44:32 +05:30
Nabin Hait
3a512af0e2 Merge pull request #10202 from nabinhait/hotfix
Minor fix in bom_stock_qty patch
2017-08-01 16:05:44 +05:30
Nabin Hait
9b2b42dfc1 Minor fix in bom_stock_qty patch 2017-08-01 11:10:29 +05:30
Makarand Bauskar
317888211a merged hotfix branch into staging (#10191)
* [Fix] Error in sales invoice and POS if customer group not defined in the customer (#10148)

* Revert "[Fix] Error in sales invoice and POS if customer group not defined in the customer (#10148)" (#10159)

This reverts commit 4d2e782e42.

* [Fix] Unable to save asset because of float error issue (#10157)

* bumped to version 8.6.4

* [Fix] Error in sales invoice and POS if customer group not defined in the customer (#10160)

* Set billing hours to 0 in timesheet #9535 (#10139)

* `update_billing_hours` to use flt not cint

* if not billable, reset billable hours

* if not billable, reset time rates

* test

* [Fix] Timesheet Company Issue

* Added delivery date in SO parent form. Fixes #10104 (#10155)

* Added delivery date in SO parent form. Fixes #10104

* UI tests for sales order delivery date

* bumped to version 8.6.5
2017-08-01 11:06:41 +05:30
mbauskar
4d185f3541 Merge branch 'hotfix' 2017-07-31 12:21:35 +05:30
mbauskar
892cd615f8 bumped to version 8.6.5 2017-07-31 12:51:35 +06:00
Nabin Hait
495ef67caa Added delivery date in SO parent form. Fixes #10104 (#10155)
* Added delivery date in SO parent form. Fixes #10104

* UI tests for sales order delivery date
2017-07-31 11:25:51 +05:30
Nabin Hait
3beb1ba667 Merge pull request #10165 from rohitwaghchaure/production_order_company_issue
[Fix] Timesheet Company Issue
2017-07-29 18:20:12 +05:30
Rohit Waghchaure
33977827c4 [Fix] Timesheet Company Issue 2017-07-29 14:15:50 +05:30
tundebabzy
41c954b8b3 Set billing hours to 0 in timesheet #9535 (#10139)
* `update_billing_hours` to use flt not cint

* if not billable, reset billable hours

* if not billable, reset time rates

* test
2017-07-28 21:05:15 +05:30
rohitwaghchaure
e2176b852e [Fix] Error in sales invoice and POS if customer group not defined in the customer (#10160) 2017-07-28 20:52:02 +05:30
mbauskar
9d5b1b0e8f Merge branch 'hotfix' 2017-07-28 16:03:52 +05:30
mbauskar
2b420f7038 bumped to version 8.6.4 2017-07-28 16:33:52 +06:00
rohitwaghchaure
353af64197 [Fix] Unable to save asset because of float error issue (#10157) 2017-07-28 15:55:46 +05:30
Makarand Bauskar
8bccaed35a Revert "[Fix] Error in sales invoice and POS if customer group not defined in the customer (#10148)" (#10159)
This reverts commit 4d2e782e42.
2017-07-28 15:43:23 +05:30
rohitwaghchaure
4d2e782e42 [Fix] Error in sales invoice and POS if customer group not defined in the customer (#10148) 2017-07-28 15:21:22 +05:30
Saurabh
c07741d36f Merge branch 'master' into staging 2017-07-27 17:50:28 +05:30
Saurabh
734e635ef6 Merge branch 'hotfix' 2017-07-27 17:50:27 +05:30
Saurabh
6f9ef5b890 bumped to version 8.6.3 2017-07-27 18:20:27 +06:00
Makarand Bauskar
145393b12f [hotfix] set the account name in GL entry instead of warehouse (#10134) 2017-07-27 16:46:40 +05:30
Makarand Bauskar
9c6e2c3637 [hotfix] included the get_purchase_trends_filters instead of get_sales_trends_filters in Purchase Receipts trends (#10127) 2017-07-27 16:23:57 +05:30
mbauskar
cfc2693b2e Merge branch 'hotfix' 2017-07-27 12:18:15 +05:30
mbauskar
448d919cc1 bumped to version 8.6.2 2017-07-27 12:48:15 +06:00
tundebabzy
87ec6a12ef adds options to currency fields (#10118) 2017-07-27 11:38:17 +05:30
rohitwaghchaure
059f99e621 [Fix] Wrong avg. buying rate in the Gross Profit report (#10110) 2017-07-27 11:37:30 +05:30
rohitwaghchaure
8579dd1d78 [minor] If customer has removed getting an error (#10107) 2017-07-27 11:21:54 +05:30
Makarand Bauskar
1d9fd9aa52 [minor][wiz] fix company image alignment (#10114) (#10117) 2017-07-26 18:19:41 +05:30
mbauskar
930dd5e54e Merge branch 'develop' into staging 2017-07-26 18:02:32 +05:30
KanchanChauhan
7800bd89dc Added Project Type new doctype to be added as link field for Project Type field in project instead of select field (#9929) 2017-07-26 17:55:25 +05:30
Utkarsh Yadav
53b877bd8f [ui test] Employee in HR (#10103)
* added test for employee

* names changed

* path added in tests.txt
2017-07-26 16:32:16 +05:30
Utkarsh Goswami
40937083bf [UI-Test Project] To check a billing cost of a project with multiple tasks (#10084)
* Updated test for Project Timesheet with multiple tasks

* Updated test for Project Timesheet with multiple tasks

* Updated test for Project Timesheet with multiple tasks

* updated:

* Updated

* Updated
2017-07-26 16:31:08 +05:30
Makarand Bauskar
d0109a6fc0 [minor] enable all roles and domain before running tests cases (#10108)
* [minor] enable all roles and domain before running tests cases

* Update utils.py
2017-07-26 16:29:22 +05:30
Utkarsh Yadav
b8a4a584e6 [ui test] test for department, designation, company and leave block list (#10085)
* added test for required items

* minor fixes for travis

* name changed

* added test for employment type

* travis fixes
2017-07-26 13:14:34 +05:30
Prateeksha Singh
cda6206c1f [minor][wiz] remove header brand image (#10016) 2017-07-26 13:05:48 +05:30
Saurabh
4c28fa77bd Merge branch 'hotfix' 2017-07-25 18:02:58 +05:30
Saurabh
7bdc45eceb Merge branch 'master' into develop 2017-07-25 18:02:58 +05:30
Saurabh
394dbca0e4 bumped to version 8.6.1 2017-07-25 18:32:58 +06:00
Saurabh
33ebd9f88e Merge pull request #10088 from saurabh6790/hot_fix_v_8_6_0
[hot][fix] updated modified date for sales order
2017-07-25 17:58:12 +05:30
Saurabh
4c1caa7e98 [hot][fix] updated modified date for sales order 2017-07-25 17:35:14 +05:30
Saurabh
dc6e369172 Merge branch 'master' into develop 2017-07-25 16:42:28 +05:30
Saurabh
08c3b3c925 Merge branch 'staging' 2017-07-25 16:42:27 +05:30
Saurabh
bb5812cf0f bumped to version 8.6.0 2017-07-25 17:12:26 +06:00
Saurabh
36645e4e2f Merge branch 'master' into staging 2017-07-25 16:15:51 +05:30
Saurabh
fb4f320df4 Merge branch 'master' into develop 2017-07-25 16:15:50 +05:30
Saurabh
b296bb1551 Merge branch 'hotfix' 2017-07-25 16:15:50 +05:30
Saurabh
e7c14fcc3d bumped to version 8.5.5 2017-07-25 16:45:49 +06:00
Saurabh
31bb34bbae Merge pull request #10081 from rohitwaghchaure/calendar_view_SO_issue_fix
[Fix] Calendar view for sales order
2017-07-25 15:54:09 +05:30
Saurabh
6436b9d089 Merge pull request #10080 from rohitwaghchaure/hotfix
[Fix] Negative amount showing in the grand total for multicurrency if discount has applied
2017-07-25 15:43:00 +05:30
Rohit Waghchaure
d62fa84ed9 [Fix] Calendar view for sales order 2017-07-25 15:34:20 +05:30
Rohit Waghchaure
baa937aa52 [Fix] Negative amount showing in the grand total for multicurrency if discount has applied 2017-07-25 15:26:01 +05:30
Ameya Shenoy
08450878f1 [ui-test] added test for bill_of_materials (#10063)
* temporary commit for switching branches

* [ui-tests] added bill_of_materials test

* fixed minor codacy problems

* added minor requested changes
2017-07-25 15:23:58 +05:30
Ashwini Save
2ffe878999 Timeline Title for small resolution Add to knowledge base button. (#9926)
* Add to Knowledge Base button class updated to hide for mobile view.

* Updated code to avoid multiple occurance of Knowledge Base button while updating comment.
2017-07-25 14:16:48 +05:30
rohitwaghchaure
49a6b4a4fa [Fix] RFQ list showing to all supplier in the portal (#10023) 2017-07-25 14:12:58 +05:30
bcornwellmott
05e51d6c83 Add Get Suppliers dialog (#10025)
* Add Get Suppliers dialog

* Commonize code, use depends_on

* Update request_for_quotation.js
2017-07-25 14:10:23 +05:30
rohitwaghchaure
4cccdbdbf9 [Fix] Validating price list currency even if price list is not defined (#10056) 2017-07-25 14:05:01 +05:30
KanchanChauhan
4b888b95d0 [Minor] Added filter condition to Customer Query (#10057) 2017-07-25 14:03:01 +05:30
Zarrar
b5ec8381a6 [UI Tests] School Academic Term test (#10050) 2017-07-25 11:46:34 +05:30
Frappe PR Bot
3b128cabb2 [Translation] Updated Translations (#10047) 2017-07-25 11:46:16 +05:30
Zarrar
1c6828e5d6 [UI Tests] School Academic Year test (#10049) 2017-07-25 11:45:39 +05:30
KanchanChauhan
d65b4b4238 Patch was faling, reload doc was missing (#10072) 2017-07-25 11:39:46 +05:30
ci2014
13abada526 Update email-account.md (#10066)
* Update email-account.md

Add information to conditional import

* Add files via upload
2017-07-25 11:06:03 +05:30
tundebabzy
de54f3019f use api to get default cost center for chosen company (#10067) 2017-07-25 11:05:07 +05:30
bcornwellmott
d023d9a0bd Add RFQ email sent check (#10068)
* Add RFQ email sent check

* remove blankspace

* Removed debugger
2017-07-25 11:03:12 +05:30
Vishal Dhayagude
edb2749dfd Timesheet web (#10037)
* [new]Timesheet added

* [new] Customer wise timesheet on webportal added
2017-07-25 10:53:12 +05:30
Makarand Bauskar
fcaf313c0f [minor] make-demo fixes for manufacturing domain (#10029) 2017-07-25 10:49:35 +05:30
Makarand Bauskar
dfc5a454b3 [minor] fixed the delivery date issue in Ordered Item to be Dellivered report (#10028) 2017-07-25 10:48:43 +05:30
bcornwellmott
1c32f5ace9 Whitelist method for adding production orders ops (#9997) 2017-07-24 22:43:44 +05:30
bcornwellmott
96381da547 Supplier Scorecard (#9294)
* Initial start of scorecard docs

* Got basic functionality working

* Fixed doc names and added key functions

* Basic functional version minus Actions

* Hide scorecard docs until functional

* Created supplier scorecard documentation

* Added default variables and standings. Added restrictions for PO + RFQ

* Automatic daily scorecard creation + on save

* Added warning for PO nd RFQs

* Minor fixes for codepy, automatically add variables for criteria, fix hooks.py typo

* Added tests, fixed codacy formatting, small improvements

* Fixed test bug w/ criteria. Codacy cleanup

* Fixed codacy issues. Fixed sticky criteria

* Fixed bug with period search. Remove blank variable child.

* Updated docs, automatically add criteria and standings, clean up period create message

* Uncommented test, set docs to beta

* Fix for nabinhait review

* Fix codacy issue. Fix dict assignment for records
2017-07-24 22:42:30 +05:30
Ameya Shenoy
91b2833708 [ui-tests] added workstation and operation (#10044)
* [ui-test] workstation and operation testing added

* [ui-tests] removed unnecessary assertions and used logical names for operations and workstations
2017-07-24 14:34:30 +05:30
Utkarsh Yadav
20a862a6b9 [ui test] holiday list and branch in HR (#10045)
* added test for holiday list

* codacy fixes

* added check for all days in list

* added test for branch

* codacy fixe

* minor fixes
2017-07-24 14:33:42 +05:30
tundebabzy
65656ec2df hide salution and gender if company type is Company (#10040) 2017-07-24 11:32:26 +05:30
Makarand Bauskar
9306aff1bb [minor] moved the patch to v8_5 and other minor fixes (#10012)
* Quotation and Supplier Quotation Route and Permission Edits

* [minor] moved the patch to v8_5 and other minor fixes
2017-07-21 15:19:47 +05:30
Ameya Shenoy
73f969fd7f [ui-test] manufacturing item creation testing (#10009) 2017-07-21 14:22:08 +05:30
Prateeksha Singh
283d5550e6 [fix] set sales base field as base_grand_total (#10008) 2017-07-21 14:21:35 +05:30
Rushabh Mehta
dda608dd00 [fix] update_company_current_month_sales in company.py (#10005) 2017-07-21 11:58:14 +05:30
Faris Ansari
e355f99786 Remove ellipsis in title and description (#9992) 2017-07-20 17:51:19 +05:30
mbauskar
27334c28a9 Merge branch 'hotfix' 2017-07-20 16:49:30 +05:30
mbauskar
6c8d4678db Merge branch 'master' into develop 2017-07-20 16:49:30 +05:30
mbauskar
ea50c9d1be bumped to version 8.5.4 2017-07-20 17:19:30 +06:00
Rushabh Mehta
35da7d1fb4 [minor] we buy is also checked by default 2017-07-20 15:58:20 +05:30
Rushabh Mehta
ced14cc789 [fix] setup-wizard 2017-07-20 15:55:54 +05:30
Rushabh Mehta
9d27cf3c62 [tests] refactored (#9984)
* [tests] refactored

* [fix] test_quotation.js

* [fix] tests.text

* [fix] fiscal year not needed

* [test] add long test

* [fix] add timeout in lead
2017-07-20 15:35:03 +05:30
mbauskar
0e6933a1e8 resolved merge conflicts 2017-07-20 14:19:47 +05:30
mbauskar
51a76885b8 Merge branch 'hotfix' 2017-07-20 14:16:57 +05:30
mbauskar
a919be111a bumped to version 8.5.3 2017-07-20 14:46:57 +06:00
Nabin Hait
9c42161061 Itemised tax breakup fix in docs other than invoice (#9961)
* Itemised tax breakup fix in docs other than invoice

* Set itemised tax breakup and hsn code in existing docs
2017-07-20 13:32:01 +05:30
rohitwaghchaure
79d6266c7b [Fix] Unable to create production order from the sales order for the bundle items (#9976) 2017-07-20 10:35:51 +05:30
tundebabzy
11d23f84d7 Can't set Start and End Dates in Salary Slip (#9513) (#9944)
* remove trigger from end_date

* adds new function `get_end_date`:
- it tries to calculate the appropriate end date for a given frequency
- returns an empty string if frequency is 'biweekly'
- adds test cases

* changes logic in `set_start_end_dates`:
- if start_date is empty in form, call process_payroll.get_start_end_dates
- else, call process_payroll.get_end_date

* `get_end_date` should return a dict

* changed "biweekly" to "bimonthly"

* change the behaviour of process payroll start and end date:
- when payroll frequency is changed, change start/end date as usual
- if start date is manually changed, use the frequency to calculate the end date

* clean up

* further cleanup

* in `get_end_date`, if `frequency` isn"t given, "monthly"

* remove end_date from cscript and introduce `set_end_date`

* fix tests

* removed whitespaces
2017-07-20 10:33:03 +05:30
Nabin Hait
8e0f23efc7 Multiple delivery dates in Sales Order and make DN based on selected delivery dates (#9933)
* Multiple delivery dates in Sales Order and make DN based on selected delivery dates

* Test case and some other minor fixes

* Updated docs for multi delivery date

* removed the trailing whitespace

* removed the trailing whitespace

* removed trailing whitespace
2017-07-20 10:30:59 +05:30
Makarand Bauskar
ac9b1332d2 [minor] set no copy to sales goal fields (#9956) 2017-07-19 18:55:12 +05:30
Doridel Cahanap
7b021e0fac Show Expected End Date in Project List View (#9964) 2017-07-19 18:21:31 +05:30
KanchanChauhan
d6dd25a666 Added indicators on Project Tasks (#9952) 2017-07-19 18:06:52 +05:30
rohitwaghchaure
f86100a734 [Fix] Calendar view not working for leave application (#9963) 2017-07-19 17:09:30 +05:30
_JG_
96bb6099d6 [fix] correctly choice 'Credit Limit' (#9932)
* [fix] correctly choice 'credit limit'

If 'Credit Days Based On' is empty in 'Supplier Type/Customer Group' then value 'Due Date' in 'Purchase/Sales Invoice' doesn't taken from the default settings

* Update party.py

* [fix] correctly choice 'Credit Limit'
2017-07-19 10:27:09 +05:30
Nabin Hait
e6c2ae3682 Merge pull request #9940 from rmehta/workstation-form
[ux] workstation form layout
2017-07-19 10:24:28 +05:30
Nabin Hait
8d56f2959b Merge pull request #9942 from bcornwellmott/bix_bom_qty
Update qty from stock_qty before validate materials
2017-07-19 10:22:00 +05:30
Rushabh Mehta
d2d24554b3 [ux] workstation form layout 2017-07-18 22:29:59 +05:30
Ben Cornwell-Mott
c7d2bc67e8 Update qty from stock_qty before validate materials 2017-07-18 08:56:25 -07:00
Rushabh Mehta
1283f6308d [fix] company graph based on base currency 2017-07-18 18:22:16 +05:30
mbauskar
d36c136fc6 Merge branch 'master' into develop 2017-07-18 16:38:24 +05:30
mbauskar
3951f6971e Merge branch 'hotfix' 2017-07-18 16:38:23 +05:30
mbauskar
75e65e7079 bumped to version 8.5.2 2017-07-18 17:08:23 +06:00
Saurabh
7f95d587b2 [fix] escape company filter (#9924) 2017-07-18 16:09:34 +05:30
Makarand Bauskar
75b145fe2c [hotfix] used frappe.db.set value instead of frappe.set_value (#9923) 2017-07-18 16:05:52 +05:30
Nabin Hait
bc3acdd0ba Merge pull request #9510 from tundebabzy/issue-9166
Unable to create Manual Depreciation of Asset due to Error #9166
2017-07-18 15:44:18 +05:30
mbauskar
8f42f60dc9 Merge branch 'hotfix' 2017-07-18 15:10:19 +05:30
mbauskar
823b3ca540 bumped to version 8.5.1 2017-07-18 15:40:19 +06:00
Makarand Bauskar
5e75e3ba03 [hotfix] set_restrict_to_domain_for_module_def patch fixes (#9921) 2017-07-18 15:09:30 +05:30
mbauskar
113df55e64 Merge branch 'develop' 2017-07-18 13:07:01 +05:30
mbauskar
3e4b2743c6 bumped to version 8.5.0 2017-07-18 13:37:00 +06:00
Nabin Hait
338c28e78e Merge pull request #9902 from rohitwaghchaure/sales_invoice_serial_no_issue_from_dn
[Fix] Sales invoice serial no validation issue
2017-07-18 13:05:50 +05:30
Rohit Waghchaure
7e14996995 [Fix] Sales invoice serial no validation issue 2017-07-18 12:59:55 +05:30
Makarand Bauskar
6e30f04181 [domainify] patch to set the restrict to domain for module_def (#9912) 2017-07-18 12:30:57 +05:30
Nabin Hait
4a10f18ee3 Merge pull request #9913 from mbauskar/quotation
[minor] fixes for TypeError: get_lead_details() takes at least 1 argument (2 given)
2017-07-18 12:20:47 +05:30
Nabin Hait
f37d43d0c1 Remove newline from serial no values 2017-07-18 12:15:16 +05:30
pratu16x7
aea60f349f [minor] default qty 0, fixes frappe/erpnext#9880 2017-07-18 12:15:16 +05:30
pratu16x7
90bd5681d1 [batch modal] bind serial_no field in onchange 2017-07-18 12:15:16 +05:30
mbauskar
30e03cc4c8 [minor] fixes for TypeError: get_lead_details() takes at least 1 argument (2 given) 2017-07-18 11:45:53 +05:30
Nabin Hait
4c40a416e6 Merge pull request #9900 from frappe/fixes_9899
[fix] #9899
2017-07-18 11:17:45 +05:30
Nabin Hait
3020c8086c Update stock_balance.py 2017-07-18 11:17:32 +05:30
Nabin Hait
8b3ef1e70a Merge pull request #9896 from rohitwaghchaure/rejected_expense_claim_issue
[Fix] Expense claim status issue
2017-07-18 11:10:52 +05:30
Makarand Bauskar
c446bf6117 Merge branch 'develop' into rejected_expense_claim_issue 2017-07-18 10:54:13 +05:30
Rushabh Mehta
660de515b5 [fix] filters for calendars frappe/erpnext#9850 (#9870) 2017-07-18 10:50:30 +05:30
Prateeksha Singh
e012e24423 Sales Goal by Company (#9723)
* [sales goal] in company; dashboard, graph, notifs, wiz

* [test] target notifications

* cache past year monthly sales of every company daily, patch

* [minor] query fixes

* update sales goal docs
2017-07-18 10:35:12 +05:30
Nabin Hait
e2d0d0a0c1 Merge pull request #9904 from nabinhait/hotfix777
Removed a deprecated function call
2017-07-17 20:29:55 +05:30
Nabin Hait
22e82dff20 Removed a deprecated function call 2017-07-17 20:28:30 +05:30
tunde
78d2f542d0 code fix as per review 2017-07-17 15:00:45 +01:00
Nabin Hait
b962fc1573 Show hsn code in tax breakup for India and render via template (#9866)
* Show hsn code in tax breakup for India and render via template

* tax breakup if gst_tax_field does not exists

* Fixed tax-breakup test cases
2017-07-17 18:02:31 +05:30
tunde
1ee534889f Revert "adds if statement for reference_type === "Asset""
This reverts commit c7e3a09cfb.
2017-07-17 13:27:59 +01:00
Frappe PR Bot
fa04236c8d [Translation] Updated Translations (#9898) 2017-07-17 17:50:36 +05:30
pawan
36025468a1 [fix] #9899 2017-07-17 17:28:44 +05:30
Rohit Waghchaure
0e376a464b test cases 2017-07-17 16:47:01 +05:30
Rohit Waghchaure
8333b5754b [Fix] Expense claim status issue 2017-07-17 16:38:20 +05:30
Rushabh Mehta
dab1172a18 [refactor] party.js get_party_details (#9888) 2017-07-17 15:31:17 +05:30
rohitwaghchaure
ea4497c8d2 Renamed the report Support Hours to Support Hours Distribution (#9874) 2017-07-17 14:55:42 +05:30
rohitwaghchaure
b994b3dcda Allow to select asset account in the payable in the expense claim for imprest management (#9891) 2017-07-17 14:33:33 +05:30
Makarand Bauskar
805a41d06c [minor] fixed the set_portal_settings patch (#9890) 2017-07-17 13:44:56 +05:30
Nabin Hait
e06526ffff Add indexes in some transaction doctypes (#9889) 2017-07-17 13:28:27 +05:30
Nabin Hait
2df7db0346 Merge pull request #9884 from mbauskar/patch-fixes
[hotfix] fixed GST code for Uttarakhand
2017-07-17 13:04:54 +05:30
Narciso E. Núñez Arias
c9877c5c1e Translation of ERPNext manual .md files (#9872)
* Translate Do I Need An ERP page

* Translate getting started with erpnext Page

* Translate Implementation Strategy Page

* Translate Spanish Index page

* Translate Flow Chart of transactions page

* Translate open source page

* Translate The Champion Page

* Fix spanish translation on Index page
2017-07-17 12:10:47 +05:30
strixaluco
372a881d8c Make 'Financial Year' translatable in Setup wizard (#9879) 2017-07-17 12:06:25 +05:30
mbauskar
71b5250cbd [hotfix] fixed the state code for Uttarakhand 2017-07-16 21:28:39 +05:30
mbauskar
ece7881ab1 Merge branch 'hotfix' 2017-07-14 17:47:07 +05:30
mbauskar
3ceebaec3f Merge branch 'master' into develop 2017-07-14 17:47:07 +05:30
mbauskar
30e987a835 bumped to version 8.4.3 2017-07-14 18:17:07 +06:00
Makarand Bauskar
087da2e571 Fixed patch (#9862) (#9871) 2017-07-14 17:44:26 +05:30
Makarand Bauskar
ad7eb9d03c [minor] check mode_of_payment in Payment entry (#9869)
* [minor] don't trigger the expense type trigger if value is not set

* [minor] check if account is selected or not in Payment Entry

* [minor] check mode_of_payment in Payment entry
2017-07-14 17:31:36 +05:30
Nabin Hait
35d0de8276 Merge pull request #9858 from mbauskar/expense-claim
[minor] don't trigger the expense type trigger if value is not set
2017-07-14 15:28:34 +05:30
Rushabh Mehta
812853aa86 [refactor] account.js to new style (#9787)
* [fix] conference site update

* [test] run all js tests
2017-07-14 15:28:04 +05:30
KanchanChauhan
319c58266b Changes Quotes to Quotations in website sidebar because that seems more legit (#9825) 2017-07-14 14:30:42 +05:30
rohitwaghchaure
dcf10ee4f6 Fixed patch (#9862) 2017-07-14 13:02:38 +05:30
mbauskar
1394a6557d [minor] check mode_of_payment in Payment entry 2017-07-14 12:09:17 +05:30
mbauskar
00e825a8af [minor] check if account is selected or not in Payment Entry 2017-07-14 11:38:39 +05:30
mbauskar
ed89a83584 [minor] don't trigger the expense type trigger if value is not set 2017-07-14 11:21:27 +05:30
Faris Ansari
2c5b3e83f5 New design for daily work summary (#9844)
* New design for daily work summary

* Update tests
2017-07-13 18:37:18 +05:30
Rushabh Mehta
8e2531e2bb Update Test Runner to run tests one by one (#9843)
* [update] tests as per new api

* [test] unset test_quotation.js

* [test] unset test_quotation.js

* [test] unset test_quotation.js

* [test] unset test_quotation.js
2017-07-13 18:22:20 +05:30
Nabin Hait
d5dd9f1706 Merge pull request #9839 from rmehta/regional-decorators
[feature] override a function regionally by adding a decorator
2017-07-13 17:51:29 +05:30
mbauskar
394c4d718d Merge branch 'develop' 2017-07-13 16:16:21 +05:30
mbauskar
ae20748dec bumped to version 8.4.2 2017-07-13 16:46:20 +06:00
Rushabh Mehta
3df2c9421a [fix] setup wont be called if declared inside setup 2017-07-13 16:11:54 +05:30
Rushabh Mehta
393becce0b [fix] name decorator as allow_regional 2017-07-13 15:49:37 +05:30
mbauskar
777b16ffda Merge branch 'develop' 2017-07-13 15:14:29 +05:30
mbauskar
efaf9f59db bumped to version 8.4.1 2017-07-13 15:44:29 +06:00
Rushabh Mehta
8f2e21def2 [feature] override a function regionally by adding a decorator 2017-07-13 15:07:51 +05:30
Rushabh Mehta
7231f29e78 [feature] override a function regionally by adding a decorator 2017-07-13 15:00:56 +05:30
Nabin Hait
239c9387d1 Merge pull request #9838 from saurabh6790/patch_fix
[patch][fix] update gst_state only if company country is india
2017-07-13 14:49:58 +05:30
Saurabh
e74e4b18c7 [patch][fix] update gst_state only if company country is india 2017-07-13 14:38:43 +05:30
mbauskar
012f5b0a50 Merge branch 'develop' 2017-07-13 14:05:51 +05:30
mbauskar
05d62127d0 bumped to version 8.4.0 2017-07-13 14:35:51 +06:00
Nabin Hait
7549a83b9b Merge pull request #9801 from manassolanki/refractor-report
changes in the assessment report
2017-07-13 13:46:19 +05:30
rohitwaghchaure
c3153655eb Fixed patch create_warehouse_nestedset (#9833) 2017-07-13 12:17:12 +05:30
Makarand Bauskar
96488b0f34 [patch] removed create company address patch (#9832) 2017-07-13 12:16:28 +05:30
Nabin Hait
1a60931435 Added SAC codes and 2/4 digit HSN codes, regional setup can be called multiple times (#9820) 2017-07-13 12:16:04 +05:30
Makarand Bauskar
8f507a984e [minor] check if the company is selected or not before triggering get_bank_cash_account (#9830)
* [minor] check if the company is selected or not before triggering get_bank_cash_account

* [minor] check if production order is available

* [minor] fixed codacy errors
2017-07-13 11:44:29 +05:30
Nabin Hait
57d3cecd68 Merge pull request #9811 from rohitwaghchaure/pricing_rule_issue_for_discount
[Fix] Manual discount is not applying in the transaction if discount amount is zero in the pricing rule
2017-07-13 11:14:53 +05:30
Nabin Hait
de609a2fb6 Merge pull request #9815 from nabinhait/develop
Set company address while making invoice from SO, don't show taxes in print if amount is zero, fixed state code
2017-07-13 11:05:55 +05:30
Nabin Hait
7312186c76 Set corrected states list in GST State field's options 2017-07-13 10:41:15 +05:30
Nabin Hait
0a32b7a6eb Set company address while making invoice from SO, don't show taxes in print if amount is zero, fixed state code 2017-07-12 19:21:05 +05:30
rohitwaghchaure
c1a1e62c0d [Fix] Data not showing in the heatmap of the customer (#9819) 2017-07-12 18:57:23 +05:30
Rohit Waghchaure
b12f2109b5 [Fix] Manual discount is not applying on the pricing rule if discount amount is zero in the pricing rule 2017-07-12 18:02:02 +05:30
Manas Solanki
a13c6a1bef codacy cleanup 2017-07-12 17:49:59 +05:30
Manas Solanki
79ed58fd36 chnages in the assessment report 2017-07-12 17:49:59 +05:30
rohitwaghchaure
860144feb7 [Fix] User not able to search an Item if description is null in the item (#9793) 2017-07-12 15:01:56 +05:30
Makarand Bauskar
1efb05233c [minor] don't trigger source_warehouse if item_code is not set in Production Order (#9806) 2017-07-12 14:53:14 +05:30
Makarand Bauskar
ef8d6dc8f8 [minor] ingore mandatory while auto closing issues and opportunity (#9783) 2017-07-12 14:52:32 +05:30
Nabin Hait
79c2191aa3 [fix] Don't add newline at the end, onchange of serial_no and filter warehouse based on company and is_group (#9809) 2017-07-12 14:10:43 +05:30
Nabin Hait
f012a9db70 Merge pull request #9812 from adityaduggal/wrong_state_codes
Changed state codes and added state
2017-07-12 14:03:39 +05:30
Aditya Duggal
4e1a3c1d58 Changed state codes and added state
-Andaman 35 added
-UP changed to 09 from 35
-Uttrakhand changed to 05 from 36
2017-07-12 13:40:11 +05:30
Nabin Hait
fb8e59234b Merge pull request #9652 from bcornwellmott/sq_lead_time
Added lead time field to supplier quotation
2017-07-11 23:39:27 +05:30
Umair Sayed
31af0849db Update navigation.md (#9798) 2017-07-11 21:07:03 +05:30
Frappe PR Bot
bfdb726072 [translation] translation updates (#9788) 2017-07-11 15:20:11 +05:30
mbauskar
a8406e1544 Merge branch 'develop' 2017-07-11 13:02:15 +05:30
mbauskar
b2aa867b70 bumped to version 8.3.6 2017-07-11 13:32:14 +06:00
Makarand Bauskar
30f2bcbccc [hotfix] allow only 5 character in company_abbr field in setup wizard (#9779) 2017-07-11 12:36:57 +05:30
Prateeksha Singh
7d885432eb [wiz] add user slide, enforce first entry, static labels (#9744) 2017-07-11 12:36:34 +05:30
Nabin Hait
3b5f774144 Merge pull request #9410 from manassolanki/patch-company
Patch for the PR 8754, fixes #9011
2017-07-11 11:35:29 +05:30
Nabin Hait
3a200bbc44 Update create_address_doc_from_address_field_in_company.py 2017-07-11 11:34:27 +05:30
Nabin Hait
2bedca04ae Merge pull request #9750 from rohitwaghchaure/taxable_amount_issue
[Fix] Taxable amount in tax breakup showing wrong value for duplicate items in the invoice
2017-07-11 11:16:56 +05:30
Manas Solanki
1a0536bff4 changes as per review 2017-07-11 11:16:16 +05:30
Manas Solanki
cdba021802 patch for removing the address field from company and creating address doc, fixes #9011 2017-07-11 11:16:16 +05:30
Shivam Mishra
3fe5ecc611 Added Lead fixture, Added test for Lead, Opportunity (#9607)
* Added fixtures for Address and Contact

* Fixed formatting errors

* Added Test for terms, Added Tax and Terms fixture

* Add tests for tax

* Added Test for Print Format
2017-07-11 10:33:07 +05:30
Rohit Waghchaure
296fbfeaac [Fix] Taxable amount in tax breakup showing wrong value for duplicate items in the invoice 2017-07-10 23:06:49 +05:30
Rushabh Mehta
4a7b4efbec [tests] update travis.yml to run ui-tests (#9748)
* [tests] update travis.yml to run ui-tests

* [tests] update travis.yml to run ui-tests

* [test] fix item_group.py

* [test] fix item_group.py

* [check] daily work summary fails?

* [check] daily work summary fails?

* [check] daily work summary fails?

* [check] daily work summary fails?

* [check] daily work summary fails?

* [check] daily work summary fails?

* [check] no scheduled jobs for tests

* [check] daily work summary fails?

* [check] daily work summary fails?
2017-07-10 23:00:01 +05:30
Ben Cornwell-Mott
b1f0fd4ac3 Lead time matches Item master 2017-07-10 09:09:29 -07:00
Nabin Hait
f7d2a59c18 Merge pull request #9538 from sagarvora/fix-bom-issue
[minor] fix bom price resetting on validation
2017-07-10 20:41:16 +05:30
Nabin Hait
0ac8542eaa Merge pull request #9772 from tundebabzy/issue-9595
Wrong Exchange Rate when making payment against Journal Entry (#9595)
2017-07-10 19:12:48 +05:30
Nabin Hait
c8b6d3badb Merge pull request #9713 from manassolanki/stud-dashb
changes in the student dashboard
2017-07-10 19:10:57 +05:30
Nabin Hait
cdf4320b3b Merge pull request #9673 from rohitwaghchaure/serial_no_sales_return_issue
Remove sales invoice from serial number while making sales return entery using delivery note
2017-07-10 19:04:30 +05:30
Nabin Hait
5b2d3222f3 Merge pull request #9710 from rohitwaghchaure/sales_invoice_dn_link_revert
Revert sales invoice dn link issue
2017-07-10 18:47:38 +05:30
Manas Solanki
5d202ca31a change in the student type 2017-07-10 18:40:53 +05:30
Nabin Hait
7088db9e1f Merge pull request #9773 from mbauskar/docs
[docs] corrected the filename from sms_setting2 -> sms_settings2
2017-07-10 18:17:28 +05:30
Nabin Hait
ec344ffa96 Merge pull request #9761 from mbauskar/depends-on
[minor] fixed depends on for stock entry expense_account and purchase receipt item's cost_center field
2017-07-10 18:16:15 +05:30
mbauskar
a52e726b6b [docs] corrected the filename from sms_setting2 -> sms_settings2 2017-07-10 18:11:32 +05:30
Nabin Hait
cf82c3828e Merge pull request #9769 from manassolanki/payment-entry
frappe call if posting date is defined
2017-07-10 17:57:26 +05:30
Nabin Hait
6fcfbaa1f9 Merge pull request #9766 from nabinhait/migration_fixes
minor fixes while upgrading an old instance
2017-07-10 17:45:25 +05:30
Nabin Hait
a6c733d06c Merge pull request #9753 from rohitwaghchaure/budget_cost_center_issue
[Fix] Budget against the field in the validation message
2017-07-10 17:45:02 +05:30
tunde
46ef26df71 treat use case where Journal entry is contained in outstanding_invoices in get_outstanding_reference_documents function 2017-07-10 13:05:29 +01:00
Manas Solanki
99d571a786 frappe call if posting date is defined 2017-07-10 17:33:27 +05:30
Rohit Waghchaure
e3ae600277 [Fix] Budget against the field in the validation message 2017-07-10 17:06:54 +05:30
Nabin Hait
dd7a723214 minor fixes while upgrading an old instance 2017-07-10 16:41:59 +05:30
mbauskar
ccaf36a00f [minor] fixed depends on for stock entry expense_account and purchase receipt item's cost_center field 2017-07-10 16:24:24 +05:30
Manas Solanki
101a021f7b added student type in program enrollment and changes in the student dashboard 2017-07-10 16:21:44 +05:30
Nabin Hait
68ed0488a3 Merge pull request #9757 from mbauskar/breadcrumb-fixes
[hotfix] check if the item group exist or not
2017-07-10 15:32:52 +05:30
mbauskar
75a233b472 [hotfix] check if the item group exist or not 2017-07-10 14:36:42 +05:30
Nabin Hait
5a174d61bc Merge pull request #9754 from creamdory/develop
Added Quotation as Standard Sidebar Menu
2017-07-10 14:13:35 +05:30
creamdory
7a2815299e Added Quotation as Standard Sidebar Menu 2017-07-10 16:09:03 +08:00
Manas Solanki
195d2b577f add few details in the student log (#9670) 2017-07-10 12:29:46 +05:30
Britlog
8c85562ceb Breadcrumbs management (#9544) 2017-07-10 12:14:05 +05:30
Manas Solanki
77aa4762b8 don't request another ajax call if one is pending (#9620) 2017-07-10 12:12:16 +05:30
Nabin Hait
35ecab6a52 Merge branch 'develop' 2017-07-08 13:55:41 +05:30
Nabin Hait
097da8cc89 bumped to version 8.3.5 2017-07-08 14:25:41 +06:00
Nabin Hait
1d52a4df22 Merge pull request #9732 from adityaduggal/gstin_NA
First 2 digit validation would disregard NA values
2017-07-08 13:52:35 +05:30
Nabin Hait
cd61a20fb4 Update utils.py 2017-07-08 13:52:13 +05:30
Nabin Hait
8f7eb358b8 Merge pull request #9730 from nabinhait/prod_fix
Finish prod order when skipped material transfer
2017-07-08 13:50:52 +05:30
Aditya Duggal
0e285265b1 First 2 digit validation would disregard NA values 2017-07-08 13:35:01 +05:30
Nabin Hait
b866fcf14f Finish prod order when skipped material transfer 2017-07-08 12:57:13 +05:30
Manas Solanki
3d190a15ab changes in the student dashboard 2017-07-07 17:29:29 +05:30
mbauskar
ab59e4769b Merge branch 'develop' 2017-07-07 17:12:37 +05:30
mbauskar
7b5ca3e494 bumped to version 8.3.4 2017-07-07 17:42:36 +06:00
Rohit Waghchaure
8f2c8f6e9d Revert sales invoice dn link issue 2017-07-07 17:07:59 +05:30
Nabin Hait
76c5924cbe Merge pull request #9699 from manassolanki/productn
frappe call only when there is item in production order
2017-07-07 15:48:37 +05:30
Nabin Hait
6eb55042d8 Merge pull request #9704 from rohitwaghchaure/serial_no_not_found_issue
Fixed the issue Serial No serial no not found
2017-07-07 15:47:25 +05:30
Rohit Waghchaure
9589527784 Fixed the issue Serial No serial no not found 2017-07-07 15:34:28 +05:30
Nabin Hait
dba3f0048b Merge pull request #9702 from mbauskar/installation-note
[hotfix] fixed the customer address set filter on Installation Note
2017-07-07 15:28:23 +05:30
mbauskar
3f6a5b2539 [hotfix] fixed the customer address set filter on Installation Note 2017-07-07 15:24:01 +05:30
Manas Solanki
cf7f72e586 frappe call only when there is item 2017-07-07 15:09:57 +05:30
Rohit Waghchaure
934e69fe0b Remove sales invoice from serial number while making sales return entery using delivery note 2017-07-06 18:19:18 +05:30
Ben Cornwell-Mott
19d9381197 Added lead time field to supplier quotation 2017-07-05 13:17:13 -07:00
Sagar Vora
7640858510 [minor] fix bom price resetting on validation 2017-06-29 22:20:07 +05:30
tunde
690de64734 Merge branch 'develop' into issue-9166 2017-06-28 13:37:04 +01:00
tunde
c7e3a09cfb adds if statement for reference_type === "Asset" 2017-06-28 13:23:18 +01:00
348 changed files with 49359 additions and 31046 deletions

View File

@@ -1,6 +1,12 @@
language: python
dist: trusty
group: deprecated-2017Q2
addons:
apt:
sources:
- google-chrome
packages:
- google-chrome-stable
python:
- "2.7"
@@ -8,43 +14,43 @@ python:
services:
- mysql
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
install:
- sudo rm /etc/apt/sources.list.d/docker.list
- sudo apt-get purge -y mysql-common mysql-server mysql-client
- nvm install v7.10.0
# - wget https://raw.githubusercontent.com/frappe/bench/master/install_scripts/setup_frappe.sh
# - sudo bash setup_frappe.sh --skip-setup-bench --mysql-root-password travis --bench-branch develop
- wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
- sudo python install.py --develop --user travis --without-bench-setup
- sudo pip install -e ~/bench
# - sudo pip install --upgrade pip
- rm $TRAVIS_BUILD_DIR/.git/shallow
- bash $TRAVIS_BUILD_DIR/travis/bench_init.sh
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
script:
before_script:
- wget http://chromedriver.storage.googleapis.com/2.27/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip
- sudo apt-get install libnss3
- sudo apt-get --only-upgrade install google-chrome-stable
- sudo cp chromedriver /usr/local/bin/.
- sudo chmod +x /usr/local/bin/chromedriver
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 3
- mysql -u root -ptravis -e 'create database test_frappe'
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
- cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench use test_site
- bench reinstall --yes
- bench build
- bench scheduler disable
- bench start &
- sleep 10
- bench --verbose run-tests --driver Firefox
before_script:
- mysql -u root -ptravis -e 'create database test_frappe'
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/92b3bea86d8c5397beef
on_success: always
on_failure: always
on_start: never
script:
- set -e
- bench --verbose run-tests
- sleep 5
- bench --verbose run-ui-tests --app erpnext

View File

@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import inspect
import frappe
from erpnext.hooks import regional_overrides
__version__ = '8.3.3'
__version__ = '8.7.0'
def get_default_company(user=None):
'''Get default company for user'''
@@ -65,3 +67,34 @@ def is_perpetual_inventory_enabled(company):
company, "enable_perpetual_inventory") or 0
return frappe.local.enable_perpetual_inventory[company]
def get_region(company=None):
'''Return the default country based on flag, company or global settings
You can also set global company flag in `frappe.flags.company`
'''
if company or frappe.flags.company:
return frappe.db.get_value('Company',
company or frappe.flags.company, 'country')
elif frappe.flags.country:
return frappe.flags.country
else:
return frappe.get_system_settings('country')
def allow_regional(fn):
'''Decorator to make a function regionally overridable
Example:
@erpnext.allow_regional
def myfunction():
pass'''
def caller(*args, **kwargs):
region = get_region()
fn_name = inspect.getmodule(fn).__name__ + '.' + fn.__name__
if region in regional_overrides and fn_name in regional_overrides[region]:
return frappe.get_attr(regional_overrides[region][fn_name])(*args, **kwargs)
else:
return fn(*args, **kwargs)
return caller

View File

@@ -1,94 +1,94 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
cur_frm.cscript.refresh = function (doc, cdt, cdn) {
if (doc.__islocal) {
frappe.msgprint(__("Please create new account from Chart of Accounts."));
throw "cannot create";
}
cur_frm.toggle_display('account_name', doc.__islocal);
// hide fields if group
cur_frm.toggle_display(['account_type', 'tax_rate'], cint(doc.is_group) == 0)
// disable fields
cur_frm.toggle_enable(['account_name', 'is_group', 'company'], false);
if (cint(doc.is_group) == 0) {
cur_frm.toggle_display('freeze_account', doc.__onload && doc.__onload.can_freeze_account);
}
// read-only for root accounts
if (!doc.parent_account) {
cur_frm.set_read_only();
cur_frm.set_intro(__("This is a root account and cannot be edited."));
} else {
// credit days and type if customer or supplier
cur_frm.set_intro(null);
cur_frm.cscript.account_type(doc, cdt, cdn);
// show / hide convert buttons
cur_frm.cscript.add_toolbar_buttons(doc);
}
}
cur_frm.add_fetch('parent_account', 'report_type', 'report_type');
cur_frm.add_fetch('parent_account', 'root_type', 'root_type');
cur_frm.cscript.account_type = function (doc, cdt, cdn) {
if (doc.is_group == 0) {
cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
cur_frm.toggle_display('warehouse', doc.account_type == 'Stock');
}
}
cur_frm.cscript.add_toolbar_buttons = function (doc) {
cur_frm.add_custom_button(__('Chart of Accounts'),
function () { frappe.set_route("Tree", "Account"); });
if (doc.is_group == 1) {
cur_frm.add_custom_button(__('Group to Non-Group'),
function () { cur_frm.cscript.convert_to_ledger(); }, 'fa fa-retweet', 'btn-default');
} else if (cint(doc.is_group) == 0) {
cur_frm.add_custom_button(__('Ledger'), function () {
frappe.route_options = {
"account": doc.name,
"from_date": frappe.sys_defaults.year_start_date,
"to_date": frappe.sys_defaults.year_end_date,
"company": doc.company
frappe.ui.form.on('Account', {
setup: function(frm) {
frm.add_fetch('parent_account', 'report_type', 'report_type');
frm.add_fetch('parent_account', 'root_type', 'root_type');
},
onload: function(frm) {
frm.set_query('parent_account', function(doc) {
return {
filters: {
"is_group": 1,
"company": doc.company
}
};
frappe.set_route("query-report", "General Ledger");
});
},
refresh: function(frm) {
if (frm.doc.__islocal) {
frappe.msgprint(__("Please create new account from Chart of Accounts."));
throw "cannot create";
}
frm.toggle_display('account_name', frm.doc.__islocal);
// hide fields if group
frm.toggle_display(['account_type', 'tax_rate'], cint(frm.doc.is_group) == 0);
// disable fields
frm.toggle_enable(['account_name', 'is_group', 'company'], false);
if (cint(frm.doc.is_group) == 0) {
frm.toggle_display('freeze_account', frm.doc.__onload
&& frm.doc.__onload.can_freeze_account);
}
// read-only for root accounts
if (!frm.doc.parent_account) {
frm.set_read_only();
frm.set_intro(__("This is a root account and cannot be edited."));
} else {
// credit days and type if customer or supplier
frm.set_intro(null);
frm.trigger('account_type');
// show / hide convert buttons
frm.trigger('add_toolbar_buttons');
}
},
account_type: function (frm) {
if (frm.doc.is_group == 0) {
frm.toggle_display(['tax_rate'], frm.doc.account_type == 'Tax');
frm.toggle_display('warehouse', frm.doc.account_type == 'Stock');
}
},
add_toolbar_buttons: function(frm) {
frm.add_custom_button(__('Chart of Accounts'),
function () { frappe.set_route("Tree", "Account"); });
if (frm.doc.is_group == 1) {
frm.add_custom_button(__('Group to Non-Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_group_to_ledger',
callback: function() {
frm.refresh();
}
});
});
} else if (cint(frm.doc.is_group) == 0) {
cur_frm.add_custom_button(__('Ledger'), function () {
frappe.route_options = {
"account": frm.doc.name,
"from_date": frappe.sys_defaults.year_start_date,
"to_date": frappe.sys_defaults.year_end_date,
"company": frm.doc.company
};
frappe.set_route("query-report", "General Ledger");
});
frm.add_custom_button(__('Non-Group to Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_ledger_to_group',
callback: function() {
frm.refresh();
}
});
});
}
cur_frm.add_custom_button(__('Non-Group to Group'),
function () { cur_frm.cscript.convert_to_group(); }, 'fa fa-retweet', 'btn-default')
}
}
cur_frm.cscript.convert_to_ledger = function (doc, cdt, cdn) {
return $c_obj(cur_frm.doc, 'convert_group_to_ledger', '', function (r, rt) {
if (r.message == 1) {
cur_frm.refresh();
}
});
}
cur_frm.cscript.convert_to_group = function (doc, cdt, cdn) {
return $c_obj(cur_frm.doc, 'convert_ledger_to_group', '', function (r, rt) {
if (r.message == 1) {
cur_frm.refresh();
}
});
}
cur_frm.fields_dict['parent_account'].get_query = function (doc) {
return {
filters: {
"is_group": 1,
"company": doc.company
}
}
}
});

View File

@@ -0,0 +1,27 @@
QUnit.module('accounts');
QUnit.test("test account", function(assert) {
assert.expect(4);
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('Tree', 'Account'),
() => frappe.click_button('Expand All'),
() => frappe.click_link('Debtors'),
() => frappe.click_button('Edit'),
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.doc.root_type=='Asset');
assert.ok(cur_frm.doc.report_type=='Balance Sheet');
assert.ok(cur_frm.doc.account_type=='Receivable');
},
() => frappe.click_button('Ledger'),
() => frappe.timeout(1),
() => {
// check if general ledger report shown
assert.deepEqual(frappe.get_route(), ['query-report', 'General Ledger']);
window.history.back();
return frappe.timeout(1);
},
() => done()
]);
});

View File

@@ -147,8 +147,9 @@ class Asset(Document):
accumulated_depreciation_after_full_schedule = \
max([d.accumulated_depreciation_amount for d in self.get("schedules")])
asset_value_after_full_schedule = (flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule))
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule),
self.precision('expected_value_after_useful_life'))
if self.expected_value_after_useful_life < asset_value_after_full_schedule:
frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")

View File

@@ -83,7 +83,7 @@ def validate_expense_against_budget(args):
budget_records = frappe.db.sql("""
select
b.{budget_against_field}, ba.budget_amount, b.monthly_distribution,
b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
b.action_if_annual_budget_exceeded,
b.action_if_accumulated_monthly_budget_exceeded
from
@@ -111,15 +111,15 @@ def validate_budget_records(args, budget_records):
args["month_end_date"] = get_last_day(args.posting_date)
compare_expense_with_budget(args, budget_amount,
_("Accumulated Monthly"), monthly_action)
_("Accumulated Monthly"), monthly_action, budget.budget_against)
if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \
and yearly_action != monthly_action:
compare_expense_with_budget(args, flt(budget.budget_amount),
_("Annual"), yearly_action)
_("Annual"), yearly_action, budget.budget_against)
def compare_expense_with_budget(args, budget_amount, action_for, action):
def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against):
actual_expense = get_actual_expense(args)
if actual_expense > budget_amount:
diff = actual_expense - budget_amount
@@ -127,7 +127,7 @@ def compare_expense_with_budget(args, budget_amount, action_for, action):
msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}").format(
_(action_for), frappe.bold(args.account), args.budget_against_field,
frappe.bold(args.budget_against),
frappe.bold(budget_against),
frappe.bold(fmt_money(budget_amount, currency=currency)),
frappe.bold(fmt_money(diff, currency=currency)))

View File

@@ -140,6 +140,33 @@ class TestBudget(unittest.TestCase):
budget.load_from_db()
budget.cancel()
def test_monthly_budget_against_parent_group_cost_center(self):
cost_center = "_Test Cost Center 3 - _TC"
if not frappe.db.exists("Cost Center", cost_center):
frappe.get_doc({
'doctype': 'Cost Center',
'cost_center_name': '_Test Cost Center 3',
'parent_cost_center': "_Test Company - _TC",
'company': '_Test Company',
'is_group': 0
}).insert(ignore_permissions=True)
budget = make_budget("Cost Center", cost_center)
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 40000, cost_center)
self.assertRaises(BudgetError, jv.submit)
budget.load_from_db()
budget.cancel()
jv.cancel()
frappe.delete_doc('Journal Entry', jv.name)
frappe.delete_doc('Cost Center', cost_center)
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
if budget_against_field == "Project":
budget_against = "_Test Project"
@@ -167,7 +194,8 @@ def make_budget(budget_against=None, cost_center=None):
if budget_against == "Project":
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Project/_Test Fiscal Year 2013%")})
else:
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", "_Test Cost Center - _TC/_Test Fiscal Year 2013%")})
cost_center_name = "{0}%".format(cost_center or "_Test Cost Center - _TC/_Test Fiscal Year 2013")
budget_list = frappe.get_all("Budget", fields=["name"], filters = {"name": ("like", cost_center_name)})
for d in budget_list:
frappe.db.sql("delete from `tabBudget` where name = %(name)s", d)
frappe.db.sql("delete from `tabBudget Account` where parent = %(name)s", d)

View File

@@ -43,8 +43,26 @@ frappe.ui.form.on("Journal Entry", {
$.each(frm.doc.accounts || [], function(i, row) {
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
})
},
company: function(frm) {
frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "Company",
filters: {"name": frm.doc.company},
fieldname: "cost_center"
},
callback: function(r){
if(r.message){
$.each(frm.doc.accounts || [], function(i, jvd) {
frappe.model.set_value(jvd.doctype, jvd.name, "cost_center", r.message.cost_center);
});
}
}
});
}
})
});
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
onload: function() {
@@ -96,7 +114,14 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
// expense claim
if(jvd.reference_type==="Expense Claim") {
return {};
return {
filters: {
'approval_status': 'Approved',
'total_sanctioned_amount': ['>', 0],
'status': ['!=', 'Paid'],
'docstatus': 1
}
};
}
// journal entry
@@ -122,10 +147,11 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
// account filter
frappe.model.validate_missing(jvd, "account");
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
} else {
}
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
// party_type and party mandatory
frappe.model.validate_missing(jvd, "party_type");
frappe.model.validate_missing(jvd, "party");

View File

@@ -291,37 +291,39 @@ frappe.ui.form.on('Payment Entry', {
set_account_currency_and_balance: function(frm, account, currency_field,
balance_field, callback_function) {
frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
args: {
"account": account,
"date": frm.doc.posting_date
},
callback: function(r, rt) {
if(r.message) {
frm.set_value(currency_field, r.message['account_currency']);
frm.set_value(balance_field, r.message['account_balance']);
if (frm.doc.posting_date && account) {
frappe.call({
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
args: {
"account": account,
"date": frm.doc.posting_date
},
callback: function(r, rt) {
if(r.message) {
frm.set_value(currency_field, r.message['account_currency']);
frm.set_value(balance_field, r.message['account_balance']);
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
frm.toggle_reqd(["reference_no", "reference_date"],
(r.message['account_type'] == "Bank" ? 1 : 0));
if(!frm.doc.received_amount && frm.doc.paid_amount)
frm.events.paid_amount(frm);
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
frm.toggle_reqd(["reference_no", "reference_date"],
(r.message['account_type'] == "Bank" ? 1 : 0));
if(frm.doc.payment_type=="Receive" && currency_field=="paid_to_account_currency") {
frm.toggle_reqd(["reference_no", "reference_date"],
(r.message['account_type'] == "Bank" ? 1 : 0));
if(!frm.doc.received_amount && frm.doc.paid_amount)
frm.events.paid_amount(frm);
} else if(frm.doc.payment_type=="Pay" && currency_field=="paid_from_account_currency") {
frm.toggle_reqd(["reference_no", "reference_date"],
(r.message['account_type'] == "Bank" ? 1 : 0));
if(!frm.doc.paid_amount && frm.doc.received_amount)
frm.events.received_amount(frm);
if(!frm.doc.paid_amount && frm.doc.received_amount)
frm.events.received_amount(frm);
}
if(callback_function) callback_function(frm);
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
}
if(callback_function) callback_function(frm);
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
}
}
});
});
}
},
paid_from_account_currency: function(frm) {

View File

@@ -492,9 +492,13 @@ def get_outstanding_reference_documents(args):
for d in outstanding_invoices:
d["exchange_rate"] = 1
if party_account_currency != company_currency \
and d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
if party_account_currency != company_currency:
if d.voucher_type in ("Sales Invoice", "Purchase Invoice"):
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
elif d.voucher_type == "Journal Entry":
d["exchange_rate"] = get_exchange_rate(
party_account_currency, company_currency, d.posting_date
)
# Get all SO / PO which are not fully billed or aginst which full advance not paid
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),

View File

@@ -721,38 +721,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tc_name",
"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": "Terms and Conditions",
"length": 0,
"no_copy": 0,
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
"permlevel": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -782,39 +750,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "territory",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Territory",
"length": 0,
"no_copy": 0,
"oldfieldname": "territory",
"oldfieldtype": "Link",
"options": "Territory",
"permlevel": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -847,6 +782,38 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tc_name",
"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": "Terms and Conditions",
"length": 0,
"no_copy": 0,
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
"permlevel": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -910,6 +877,129 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer_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": "New Customer Details",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "territory",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Territory",
"length": 0,
"no_copy": 0,
"oldfieldname": "territory",
"oldfieldtype": "Link",
"options": "Territory",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_31",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer_group",
"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": "Customer Group",
"length": 0,
"no_copy": 0,
"options": "Customer Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1201,7 +1291,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-16 17:04:33.165676",
"modified": "2017-07-28 03:40:03.253088",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -14,6 +14,7 @@ class POSProfile(Document):
self.check_for_duplicate()
self.validate_all_link_fields()
self.validate_duplicate_groups()
self.validate_customer_territory_group()
def check_for_duplicate(self):
res = frappe.db.sql("""select name, user from `tabPOS Profile`
@@ -48,6 +49,13 @@ class POSProfile(Document):
if len(customer_groups) != len(set(customer_groups)):
frappe.throw(_("Duplicate customer group found in the cutomer group table"), title = "Duplicate Customer Group")
def validate_customer_territory_group(self):
if not self.territory:
frappe.throw(_("Territory is Required in POS Profile"), title="Mandatory Field")
if not self.customer_group:
frappe.throw(_("Customer Group is Required in POS Profile"), title="Mandatory Field")
def before_save(self):
set_account_for_mode_of_payment(self)

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: POS Profile", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially('POS Profile', [
// insert a new POS Profile
() => frappe.tests.make([
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@@ -42,6 +42,7 @@ def make_pos_profile():
"naming_series": "_T-POS Profile-",
"selling_price_list": "_Test Price List",
"territory": "_Test Territory",
"customer_group": frappe.db.get_value('Customer Group', {'is_group': 0}, 'name'),
"warehouse": "_Test Warehouse - _TC",
"write_off_account": "_Test Write Off - _TC",
"write_off_cost_center": "_Test Write Off Cost Center - _TC"

View File

@@ -185,7 +185,7 @@ def get_pricing_rule_for_item(args):
"discount_percentage": 0.0
})
else:
item_details.discount_percentage = pricing_rule.discount_percentage
item_details.discount_percentage = pricing_rule.discount_percentage or args.discount_percentage
elif args.get('pricing_rule'):
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)

View File

@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import unittest
import frappe
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
@@ -248,4 +249,51 @@ class TestPricingRule(unittest.TestCase):
so.submit()
so = frappe.get_doc('Sales Order', so.name)
self.assertEquals(so.items[0].discount_percentage, 0)
self.assertEquals(so.items[0].rate, 100)
self.assertEquals(so.items[0].rate, 100)
def test_pricing_rule_with_margin_and_discount(self):
make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10)
si = create_sales_invoice(do_not_save=True)
si.items[0].price_list_rate = 1000
si.insert(ignore_permissions=True)
item = si.items[0]
self.assertEquals(item.rate, 1100)
self.assertEquals(item.margin_rate_or_amount, 10)
# With discount
item.discount_percentage = 10
si.save()
item = si.items[0]
self.assertEquals(item.rate, 990)
self.assertEquals(item.discount_percentage, 10)
frappe.db.sql("delete from `tabPricing Rule`")
def make_pricing_rule(**args):
args = frappe._dict(args)
doc = frappe.get_doc({
"doctype": "Pricing Rule",
"title": args.title or "_Test Pricing Rule",
"company": args.company or "_Test Company",
"apply_on": args.apply_on or "Item Code",
"item_code": args.item_code or "_Test Item",
"applicable_for": args.applicable_for,
"selling": args.selling or 0,
"buying": args.buying or 0,
"min_qty": args.min_qty or 0.0,
"max_qty": args.max_qty or 0.0,
"price_or_discount": args.price_or_discount or "Discount Percentage",
"discount_percentage": args.discount_percentage or 0.0,
"price": args.price or 0.0,
"margin_type": args.margin_type,
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0
}).insert(ignore_permissions=True)
apply_on = doc.apply_on.replace(' ', '_').lower()
if args.get(apply_on) and apply_on != "item_code":
doc.db_set(apply_on, args.get(apply_on))
applicable_for = doc.applicable_for.replace(' ', '_').lower()
if args.get(applicable_for):
doc.db_set(applicable_for, args.get(applicable_for))

View File

@@ -1516,6 +1516,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "sec_tax_breakup",
"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": "Tax Breakup",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1523,7 +1553,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1533,12 +1563,12 @@
"in_standard_filter": 0,
"label": "Taxes and Charges Calculation",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"oldfieldtype": "HTML",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -3767,7 +3797,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-29 10:48:09.707735",
"modified": "2017-07-19 13:53:48.673757",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.utils import nowdate
from erpnext.setup.utils import get_exchange_rate
from frappe.core.doctype.communication.email import make
@@ -20,6 +21,7 @@ def get_pos_data():
if pos_profile.get('name'):
pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name'))
pos_profile.validate()
company_data = get_company_data(doc.company)
update_pos_profile_data(doc, pos_profile, company_data)
@@ -378,13 +380,27 @@ def add_customer(data):
customer_doc.customer_name = data.get('full_name') or data.get('customer')
customer_doc.customer_pos_id = data.get('customer_pos_id')
customer_doc.customer_type = 'Company'
customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group')
customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory')
customer_doc.customer_group = get_customer_group(data)
customer_doc.territory = get_territory(data)
customer_doc.flags.ignore_mandatory = True
customer_doc.save(ignore_permissions = True)
frappe.db.commit()
return customer_doc.name
def get_territory(data):
if data.get('territory'):
return data.get('territory')
return frappe.db.get_single_value('Selling Settings',
'territory') or _('All Territories')
def get_customer_group(data):
if data.get('customer_group'):
return data.get('customer_group')
return frappe.db.get_single_value('Selling Settings',
'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
def make_contact(args,customer):
if args.get('email_id') or args.get('phone'):
name = frappe.db.get_value('Dynamic Link',

View File

@@ -98,6 +98,26 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.set_default_print_format();
},
on_submit: function(doc, dt, dn) {
var me = this;
$.each(doc["items"], function(i, row) {
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
})
if(this.frm.doc.is_pos) {
this.frm.msgbox = frappe.msgprint(
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
${__('Print')}</a>
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
${__('New')}</a>`
);
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
this.frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
}
},
set_default_print_format: function() {
// set default print format to POS type
if(cur_frm.doc.is_pos) {
@@ -306,7 +326,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.frm.refresh_fields();
},
company_address: function() {
var me = this;
if(this.frm.doc.company_address) {
@@ -343,13 +363,6 @@ cur_frm.cscript.hide_fields = function(doc) {
}
}
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
'warehouse', 'expense_account', 'quality_inspection']
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
// India related fields
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
else hide_field(['c_form_applicable', 'c_form_no']);
@@ -445,24 +458,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
$.each(doc["items"], function(i, row) {
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
})
if(cur_frm.doc.is_pos) {
cur_frm.msgbox = frappe.msgprint(
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
${__('Print')}</a>
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
${__('New')}</a>`
);
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
cur_frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
}
}
cur_frm.set_query("debit_to", function(doc) {
// filter on Account
if (doc.customer) {

View File

@@ -18,6 +18,7 @@ from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timeshe
from erpnext.accounts.doctype.asset.depreciation \
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
from erpnext.stock.doctype.batch.batch import set_batch_nos
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -83,10 +84,10 @@ class SalesInvoice(SellingController):
if not self.is_opening:
self.is_opening = 'No'
if self._action != 'submit' and self.update_stock and not self.is_return:
set_batch_nos(self, 'warehouse', True)
self.set_against_income_account()
self.validate_c_form()
@@ -98,7 +99,7 @@ class SalesInvoice(SellingController):
self.set_billing_hours_and_amount()
self.update_timesheet_billing_for_project()
self.set_status()
def before_save(self):
set_account_for_mode_of_payment(self)
@@ -139,6 +140,8 @@ class SalesInvoice(SellingController):
self.update_time_sheet(self.name)
frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales', company=self.company)
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
frappe.throw(_("At least one mode of payment is required for POS invoice."))
@@ -803,19 +806,27 @@ class SalesInvoice(SellingController):
continue
for serial_no in item.serial_no.split("\n"):
sno = frappe.get_doc('Serial No', serial_no)
sno.sales_invoice = invoice
sno.db_update()
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()
def validate_serial_numbers(self):
"""
validate serial number agains Delivery Note and Sales Invoice
"""
self.set_serial_no_against_delivery_note()
self.validate_serial_against_delivery_note()
self.validate_serial_against_sales_invoice()
def set_serial_no_against_delivery_note(self):
for item in self.items:
if item.serial_no and item.delivery_note and \
item.qty != len(get_serial_nos(item.serial_no)):
item.serial_no = get_delivery_note_serial_no(item.item_code, item.qty, item.delivery_note)
def validate_serial_against_delivery_note(self):
"""
"""
validate if the serial numbers in Sales Invoice Items are same as in
Delivery Note Item
"""
@@ -825,14 +836,18 @@ class SalesInvoice(SellingController):
continue
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
dn_serial_nos = set(serial_nos.split("\n"))
dn_serial_nos = set(get_serial_nos(serial_nos))
serial_nos = item.serial_no or ""
si_serial_nos = set(serial_nos.split("\n"))
si_serial_nos = set(get_serial_nos(serial_nos))
if si_serial_nos - dn_serial_nos:
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
if item.serial_no and cint(item.qty) != len(si_serial_nos):
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.".format(
item.idx, item.qty, item.item_code, len(si_serial_nos))))
def validate_serial_against_sales_invoice(self):
""" check if serial number is already used in other sales invoice """
for item in self.items:
@@ -917,7 +932,6 @@ def make_delivery_note(source_name, target_doc=None):
return doclist
@frappe.whitelist()
def make_sales_return(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc

View File

@@ -11,8 +11,7 @@ def get_data():
'Sales Invoice': 'return_against'
},
'internal_links': {
'Sales Order': ['items', 'sales_order'],
'Delivery Note': ['items', 'delivery_note']
'Sales Order': ['items', 'sales_order']
},
'transactions': [
{

View File

@@ -13,6 +13,7 @@ from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
from frappe.model.naming import make_autoname
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -1105,8 +1106,83 @@ class TestSalesInvoice(unittest.TestCase):
for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.get(k), expected_values[d.item_code][i])
def test_item_wise_tax_breakup(self):
def test_item_wise_tax_breakup_india(self):
frappe.flags.country = "India"
si = self.create_si_to_test_tax_breakup()
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
expected_itemised_tax = {
"999800": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 1500.0
}
}
}
expected_itemised_taxable_amount = {
"999800": 15000.0
}
self.assertEqual(itemised_tax, expected_itemised_tax)
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
frappe.flags.country = None
def test_item_wise_tax_breakup_outside_india(self):
frappe.flags.country = "United States"
si = self.create_si_to_test_tax_breakup()
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
expected_itemised_tax = {
"_Test Item": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 1000.0
}
},
"_Test Item 2": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 500.0
}
}
}
expected_itemised_taxable_amount = {
"_Test Item": 10000.0,
"_Test Item 2": 5000.0
}
self.assertEqual(itemised_tax, expected_itemised_tax)
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
frappe.flags.country = None
def create_si_to_test_tax_breakup(self):
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 100,
"rate": 50,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC"
})
si.append("items", {
"item_code": "_Test Item 2",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 100,
"rate": 50,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC"
})
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
@@ -1115,11 +1191,7 @@ class TestSalesInvoice(unittest.TestCase):
"rate": 10
})
si.insert()
tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th><th class="text-right" style="min-width: 80px;">Taxable Amount</th><th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">\u20b9 5,000.00</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
self.assertEqual(si.other_charges_calculation, tax_breakup_html)
return si
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
@@ -1140,6 +1212,7 @@ def create_sales_invoice(**args):
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
"gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
"rate": args.rate or 100,

View File

@@ -1424,7 +1424,7 @@
"collapsible": 1,
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
"columns": 0,
"depends_on": "eval: parent.update_stock",
"depends_on": "",
"fieldname": "warehouse_and_reference",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2166,7 +2166,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-07-06 17:54:03.347700",
"modified": "2017-07-17 17:54:48.246507",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -20,20 +20,22 @@ frappe.ui.form.on("Tax Rule", "refresh", function(frm) {
})
frappe.ui.form.on("Tax Rule", "customer", function(frm) {
frappe.call({
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
args: {
"party": frm.doc.customer,
"party_type": "customer"
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frm.set_value(k, v);
});
if(frm.doc.customer) {
frappe.call({
method:"erpnext.accounts.doctype.tax_rule.tax_rule.get_party_details",
args: {
"party": frm.doc.customer,
"party_type": "customer"
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frm.set_value(k, v);
});
}
}
}
});
});
}
});
frappe.ui.form.on("Tax Rule", "supplier", function(frm) {

View File

@@ -979,6 +979,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
get_prompt_details: function() {
this.prompt_details = this.customer_doc.get_values();
this.prompt_details['country'] = this.pos_profile_data.country;
this.prompt_details['territory'] = this.pos_profile_data["territory"];
this.prompt_details['customer_group'] = this.pos_profile_data["customer_group"];
this.prompt_details['customer_pos_id'] = this.customer_doc.fields_dict.customer_pos_id.value;
return JSON.stringify(this.prompt_details)
},
@@ -1078,7 +1080,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
} else if (item.barcode == me.serach_item.$input.val()) {
search_status = false;
return item.barcode == me.serach_item.$input.val();
} else if (reg.test(item.item_code.toLowerCase()) || reg.test(item.description.toLowerCase()) ||
} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) ||
reg.test(item.item_name.toLowerCase()) || reg.test(item.item_group.toLowerCase())) {
return true
}
@@ -1351,7 +1353,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.child.item_name = this.items[0].item_name;
this.child.stock_uom = this.items[0].stock_uom;
this.child.brand = this.items[0].brand;
this.child.description = this.items[0].description;
this.child.description = this.items[0].description || this.items[0].item_name;
this.child.discount_percentage = 0.0;
this.child.qty = 1;
this.child.item_group = this.items[0].item_group;
@@ -1398,10 +1400,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
return erpnext.get_currency(this.frm.doc.company);
},
show_item_wise_taxes: function () {
return null;
},
show_items_in_item_cart: function () {
var me = this;
var $items = this.wrapper.find(".items").empty();

View File

@@ -8,9 +8,10 @@ import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.model.utils import get_fetch_values
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
add_years, get_timestamp, nowdate, flt
from frappe.contacts.doctype.address.address import get_address_display, get_default_address
from frappe.utils import (add_days, getdate, formatdate, get_first_day, date_diff,
add_years, get_timestamp, nowdate, flt)
from frappe.contacts.doctype.address.address import (get_address_display,
get_default_address, get_company_address)
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
@@ -77,8 +78,9 @@ def set_address_details(out, party, party_type, doctype=None, company=None):
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
if doctype and doctype in ['Sales Invoice']:
out.company_address = get_default_address('Company', company)
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
out.update(get_company_address(company))
if out.company_address:
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
def set_contact_details(out, party, party_type):
out.contact_person = get_default_contact(party_type, party.name)
@@ -271,6 +273,7 @@ def get_due_date(posting_date, party_type, party, company):
return due_date
def get_credit_days(party_type, party, company):
credit_days = 0
if party_type and party:
if party_type == "Customer":
credit_days_based_on, credit_days, customer_group = \
@@ -280,14 +283,16 @@ def get_credit_days(party_type, party, company):
frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "supplier_type"])
if not credit_days_based_on:
if party_type == "Customer":
if party_type == "Customer" and customer_group:
credit_days_based_on, credit_days = \
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"]) \
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
else:
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"])
elif party_type == "Supplier" and supplier_type:
credit_days_based_on, credit_days = \
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])\
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"] )
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])
if not credit_days_based_on:
credit_days_based_on, credit_days = \
frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
return credit_days_based_on, credit_days

View File

@@ -209,7 +209,10 @@ class GrossProfitGenerator(object):
sle.voucher_detail_no == row.item_row:
previous_stock_value = len(my_sle) > i+1 and \
flt(my_sle[i+1].stock_value) or 0.0
return previous_stock_value - flt(sle.stock_value)
if previous_stock_value:
return previous_stock_value - flt(sle.stock_value)
else:
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
else:
return flt(row.qty) * self.get_average_buying_rate(row, item_code)

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -1546,6 +1546,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "sec_tax_breakup",
"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": "Tax Breakup",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1553,7 +1583,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1568,7 +1598,7 @@
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -3305,7 +3335,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:21.066814",
"modified": "2017-07-19 14:03:51.838328",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -39,6 +39,8 @@ class PurchaseOrder(BuyingController):
super(PurchaseOrder, self).validate()
self.set_status()
self.validate_supplier()
validate_for_items(self)
self.check_for_closed_status()
@@ -65,6 +67,17 @@ class PurchaseOrder(BuyingController):
}
})
def validate_supplier(self):
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
if prevent_po:
standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
frappe.throw(_("Purchase Orders are not allowed for {0} due to a scorecard standing of {1}.").format(self.supplier, standing))
warn_po = frappe.db.get_value("Supplier", self.supplier, 'warn_pos')
if warn_po:
standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and Purchase Orders to this supplier should be issued with caution.").format(self.supplier, standing), title=_("Caution"), indicator='orange')
def validate_minimum_order_qty(self):
items = list(set([d.item_code for d in self.get("items")]))

View File

@@ -11,3 +11,6 @@ from erpnext.controllers.print_settings import print_settings_for_item_table
class PurchaseOrderItem(Document):
def __setup__(self):
print_settings_for_item_table(self)
def on_doctype_update():
frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])

View File

@@ -44,6 +44,9 @@ frappe.ui.form.on("Request for Quotation",{
freeze: true,
args: {
rfq_name: frm.doc.name
},
callback: function(r){
frm.reload_doc();
}
});
});
@@ -51,6 +54,91 @@ frappe.ui.form.on("Request for Quotation",{
},
get_suppliers_button: function (frm) {
var doc = frm.doc;
var dialog = new frappe.ui.Dialog({
title: __("Get Suppliers"),
fields: [
{ "fieldtype": "Select", "label": __("Get Suppliers By"),
"fieldname": "search_type",
"options": "Tag\nSupplier Type", "reqd": 1 },
{ "fieldtype": "Link", "label": __("Supplier Type"),
"fieldname": "supplier_type",
"options": "Supplier Type", "reqd": 0,
"depends_on": "eval:doc.search_type == 'Supplier Type'"},
{ "fieldtype": "Data", "label": __("Tag"),
"fieldname": "tag", "reqd": 0,
"depends_on": "eval:doc.search_type == 'Tag'" },
{ "fieldtype": "Button", "label": __("Add All Suppliers"),
"fieldname": "add_suppliers", "cssClass": "btn-primary"},
]
});
dialog.fields_dict.add_suppliers.$input.click(function() {
var args = dialog.get_values();
if(!args) return;
dialog.hide();
//Remove blanks
for (var j = 0; j < frm.doc.suppliers.length; j++) {
if(!frm.doc.suppliers[j].hasOwnProperty("supplier")) {
frm.get_field("suppliers").grid.grid_rows[j].remove();
}
}
function load_suppliers(r) {
if(r.message) {
for (var i = 0; i < r.message.length; i++) {
var exists = false;
if (r.message[i].constructor === Array){
var supplier = r.message[i][0];
} else {
var supplier = r.message[i].name;
}
for (var j = 0; j < doc.suppliers.length;j++) {
if (supplier === doc.suppliers[j].supplier) {
exists = true;
}
}
if(!exists) {
var d = frm.add_child('suppliers');
d.supplier = supplier;
frm.script_manager.trigger("supplier", d.doctype, d.name);
}
}
}
frm.refresh_field("suppliers");
}
if (args.search_type === "Tag" && args.tag) {
return frappe.call({
type: "GET",
method: "frappe.desk.tags.get_tagged_docs",
args: {
"doctype": "Supplier",
"tag": args.tag
},
callback: load_suppliers
});
} else if (args.supplier_type) {
return frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "Supplier",
order_by: "name",
fields: ["name"],
filters: [["Supplier", "supplier_type", "=", args.supplier_type]]
},
callback: load_suppliers
});
}
});
dialog.show();
},
make_suppplier_quotation: function(frm) {
var doc = frm.doc;
var dialog = new frappe.ui.Dialog({

View File

@@ -25,7 +25,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
@@ -59,7 +59,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
@@ -156,7 +156,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Date",
"length": 0,
@@ -236,6 +236,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "get_suppliers_button",
"fieldtype": "Button",
"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": "Get Suppliers",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -406,7 +436,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Message for Supplier",
"length": 0,
@@ -786,7 +816,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:13.171291",
"modified": "2017-07-21 14:06:46.309322",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation",

View File

@@ -21,6 +21,7 @@ STANDARD_USERS = ("Guest", "Administrator")
class RequestforQuotation(BuyingController):
def validate(self):
self.validate_duplicate_supplier()
self.validate_supplier_list()
validate_for_items(self)
self.update_email_id()
@@ -29,6 +30,17 @@ class RequestforQuotation(BuyingController):
if len(supplier_list) != len(set(supplier_list)):
frappe.throw(_("Same supplier has been entered multiple times"))
def validate_supplier_list(self):
for d in self.suppliers:
prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, 'prevent_rfqs')
if prevent_rfqs:
standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
frappe.throw(_("RFQs are not allowed for {0} due to a scorecard standing of {1}").format(d.supplier, standing))
warn_rfqs = frappe.db.get_value("Supplier", d.supplier, 'warn_rfqs')
if warn_rfqs:
standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and RFQs to this supplier should be issued with caution.").format(d.supplier, standing), title=_("Caution"), indicator='orange')
def update_email_id(self):
for rfq_supplier in self.suppliers:
if not rfq_supplier.email_id:
@@ -40,6 +52,8 @@ class RequestforQuotation(BuyingController):
def on_submit(self):
frappe.db.set(self, 'status', 'Submitted')
for supplier in self.suppliers:
supplier.email_sent = 0
def on_cancel(self):
frappe.db.set(self, 'status', 'Cancelled')
@@ -54,6 +68,8 @@ class RequestforQuotation(BuyingController):
self.update_supplier_part_no(rfq_supplier)
self.supplier_rfq_mail(rfq_supplier, update_password_link, self.get_link())
rfq_supplier.email_sent = 1
rfq_supplier.save()
def get_link(self):
# RFQ link for supplier portal
@@ -84,7 +100,10 @@ class RequestforQuotation(BuyingController):
else:
contact = frappe.new_doc("Contact")
contact.first_name = rfq_supplier.supplier_name or rfq_supplier.supplier
contact.supplier = rfq_supplier.supplier
contact.append('links', {
'link_doctype': 'Supplier',
'link_name': rfq_supplier.supplier
})
if not contact.email_id and not contact.user:
contact.email_id = user.name

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -12,6 +13,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -42,6 +44,39 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"depends_on": "eval:doc.docstatus >= 1",
"fieldname": "email_sent",
"fieldtype": "Check",
"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": "Email Sent",
"length": 0,
"no_copy": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +107,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -102,6 +138,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -130,6 +167,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -160,6 +198,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -190,6 +229,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -219,17 +259,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-17 16:42:57.254211",
"modified": "2017-07-24 06:52:19.542717",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation Supplier",

View File

@@ -322,6 +322,126 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_rfqs",
"fieldtype": "Check",
"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": "Warn RFQs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_pos",
"fieldtype": "Check",
"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": "Warn POs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_rfqs",
"fieldtype": "Check",
"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": "Prevent RFQs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_pos",
"fieldtype": "Check",
"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": "Prevent POs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -850,7 +970,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:16.310834",
"modified": "2017-07-06 16:40:46.935608",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",

View File

@@ -1120,6 +1120,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "tax_breakup",
"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": "Tax Breakup",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1127,7 +1157,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1142,7 +1172,7 @@
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -2217,7 +2247,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-13 14:28:54.466450",
"modified": "2017-07-19 13:51:18.929697",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -44,6 +46,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -73,34 +76,7 @@
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -131,6 +107,66 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "lead_time_days",
"fieldtype": "Int",
"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": "Lead Time in days",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -160,6 +196,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -192,6 +229,7 @@
"width": "300px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -219,6 +257,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -248,6 +287,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -278,6 +318,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -306,6 +347,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -338,6 +380,7 @@
"width": "60px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -368,6 +411,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -397,6 +441,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -426,6 +471,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -453,6 +499,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -486,6 +533,7 @@
"width": "100px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -515,6 +563,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -544,6 +593,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -571,6 +621,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -602,6 +653,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -633,6 +685,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -660,6 +713,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -694,6 +748,7 @@
"width": "100px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -725,6 +780,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -754,6 +810,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -782,6 +839,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -811,6 +869,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -841,6 +900,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -869,6 +929,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -899,6 +960,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -929,6 +991,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -957,6 +1020,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -988,6 +1052,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1017,6 +1082,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1047,6 +1113,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1080,6 +1147,7 @@
"width": "120px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1110,6 +1178,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1137,6 +1206,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1167,6 +1237,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1196,6 +1267,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1227,6 +1299,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1259,6 +1332,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1290,6 +1364,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1318,6 +1393,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1347,6 +1423,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -1377,17 +1454,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-17 16:43:59.582188",
"modified": "2017-07-10 09:08:52.015387",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",

View File

@@ -0,0 +1,146 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe, refresh_field */
frappe.ui.form.on("Supplier Scorecard", {
onload: function(frm) {
if (frm.doc.indicator_color !== "") {
frm.set_indicator_formatter("status", function(doc) {
return doc.indicator_color.toLowerCase();
});
}
if (frm.doc.__unsaved == 1) {
loadAllCriteria(frm);
loadAllStandings(frm);
}
},
refresh: function(frm) {
if (frm.dashboard.hasOwnProperty('heatmap')) {
frm.dashboard.heatmap.setLegend([0,20,40,60,80,101],["#991600","#169900"]);
}
}
});
frappe.ui.form.on("Supplier Scorecard Scoring Standing", {
standing_name: function(frm, cdt, cdn) {
if (frm.doc.standing_name != undefined) {
var d = frappe.get_doc(cdt, cdn);
return frm.call({
method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_scoring_standing",
child: d,
args: {
standing_name: d.standing_name
}
});
}
}
});
frappe.ui.form.on("Supplier Scorecard Scoring Variable", {
variable_label: function(frm, cdt, cdn) {
if (frm.doc.variable_label != undefined) {
var d = frappe.get_doc(cdt, cdn);
return frm.call({
method: "erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable.get_scoring_variable",
child: d,
args: {
variable_label: d.variable_label
}
});
}
}
});
frappe.ui.form.on("Supplier Scorecard Scoring Criteria", {
criteria_name: function(frm, cdt, cdn) {
if (frm.doc.criteria_name != undefined) {
var d = frappe.get_doc(cdt, cdn);
frm.call({
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_variables",
args: {
criteria_name: d.criteria_name
},
callback: function(r) {
for (var i = 0; i < r.message.length; i++)
{
var exists = false;
for (var j = 0; j < frm.doc.variables.length; j++)
{
if(!frm.doc.variables[j].hasOwnProperty("variable_label")) {
frm.get_field("variables").grid.grid_rows[j].remove();
}
else if(frm.doc.variables[j].variable_label === r.message[i]) {
exists = true;
}
}
if (!exists){
var new_row = frm.add_child("variables");
new_row.variable_label = r.message[i];
frm.script_manager.trigger("variable_label", new_row.doctype, new_row.name);
}
}
refresh_field("variables");
}
});
return frm.call({
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_scoring_criteria",
child: d,
args: {
criteria_name: d.criteria_name
}
});
}
}
});
var loadAllCriteria = function(frm) {
frappe.call({
method: "erpnext.buying.doctype.supplier_scorecard_criteria.supplier_scorecard_criteria.get_criteria_list",
callback: function(r) {
for (var j = 0; j < frm.doc.criteria.length; j++)
{
if(!frm.doc.criteria[j].hasOwnProperty("criteria_name")) {
frm.get_field("criteria").grid.grid_rows[j].remove();
}
}
for (var i = 0; i < r.message.length; i++)
{
var new_row = frm.add_child("criteria");
new_row.criteria_name = r.message[i].name;
frm.script_manager.trigger("criteria_name", new_row.doctype, new_row.name);
}
refresh_field("criteria");
}
});
};
var loadAllStandings = function(frm) {
frappe.call({
method: "erpnext.buying.doctype.supplier_scorecard_standing.supplier_scorecard_standing.get_standings_list",
callback: function(r) {
for (var j = 0; j < frm.doc.standings.length; j++)
{
if(!frm.doc.standings[j].hasOwnProperty("standing_name")) {
frm.get_field("standings").grid.grid_rows[j].remove();
}
}
for (var i = 0; i < r.message.length; i++)
{
var new_row = frm.add_child("standings");
new_row.standing_name = r.message[i].name;
frm.script_manager.trigger("standing_name", new_row.doctype, new_row.name);
}
refresh_field("standings");
}
});
};

View File

@@ -0,0 +1,701 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:supplier",
"beta": 1,
"creation": "2017-05-29 01:40:54.786555",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "supplier",
"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": "Supplier",
"length": 0,
"no_copy": 0,
"options": "Supplier",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "supplier_score",
"fieldtype": "Data",
"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": "Supplier Score",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "indicator_color",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Indicator Color",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "status",
"fieldtype": "Data",
"hidden": 1,
"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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Per Month",
"fieldname": "period",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Evaluation Period",
"length": 0,
"no_copy": 0,
"options": "Per Month\nPer Week\nPer Year",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "scoring_setup",
"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": "Scoring Setup",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
"description": "Scorecard variables can be used, as well as:\n{total_score} (the total score from that period),\n{period_number} (the number of periods to present day)\n",
"fieldname": "weighting_function",
"fieldtype": "Small Text",
"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": "Weighting Function",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "standings",
"fieldtype": "Table",
"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": "Scoring Standings",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Scoring Standing",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "criteria_setup",
"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": "Criteria Setup",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "criteria",
"fieldtype": "Table",
"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": "Scoring Criteria",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Scoring Criteria",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "variables",
"fieldtype": "Table",
"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": "Supplier Variables",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Scoring Variable",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "eval: doc.status != 'Unknown'",
"columns": 0,
"fieldname": "scorecard_actions",
"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": "Scorecard Actions",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_rfqs",
"fieldtype": "Check",
"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": "Warn for new Request for Quotations",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_pos",
"fieldtype": "Check",
"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": "Warn for new Purchase Orders",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_rfqs",
"fieldtype": "Check",
"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": "Prevent RFQs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_pos",
"fieldtype": "Check",
"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": "Prevent POs",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_16",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_supplier",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Supplier",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_employee",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Employee",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee",
"length": 0,
"no_copy": 0,
"options": "Employee",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-12 07:33:11.874949",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -0,0 +1,262 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import throw, _
from frappe.model.document import Document
import time
from datetime import timedelta
from frappe.utils import nowdate, get_last_day, getdate, add_days, add_years
from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import make_supplier_scorecard
class SupplierScorecard(Document):
def validate(self):
self.validate_standings()
self.validate_criteria_weights()
self.calculate_total_score()
self.update_standing()
def on_update(self):
score = make_all_scorecards(self.name)
if score > 0:
self.save()
def validate_standings(self):
# Check that there are no overlapping scores and check that there are no missing scores
score = 0
for c1 in self.standings:
for c2 in self.standings:
if c1 != c2:
if (c1.max_grade > c2.min_grade and c1.min_grade < c2.max_grade):
throw(_('Overlap in scoring between {0} and {1}').format(c1.standing_name,c2.standing_name))
if c2.min_grade == score:
score = c2.max_grade
if score < 100:
throw(_('Unable to find score starting at {0}. You need to have standing scores covering 0 to 100').format(score))
def validate_criteria_weights(self):
weight = 0
for c in self.criteria:
weight += c.weight
if weight != 100:
throw(_('Criteria weights must add up to 100%'))
def calculate_total_score(self):
scorecards = frappe.db.sql("""
SELECT
scp.name
FROM
`tabSupplier Scorecard Period` scp
WHERE
scp.scorecard = %(sc)s
ORDER BY
scp.end_date DESC""",
{"sc": self.name}, as_dict=1)
period = 0
total_score = 0
total_max_score = 0
for scp in scorecards:
my_sc = frappe.get_doc('Supplier Scorecard Period', scp.name)
my_scp_weight = self.weighting_function
my_scp_weight = my_scp_weight.replace('{period_number}', str(period))
my_scp_maxweight = my_scp_weight.replace('{total_score}', '100')
my_scp_weight = my_scp_weight.replace('{total_score}', str(my_sc.total_score))
max_score = my_sc.calculate_weighted_score(my_scp_maxweight)
score = my_sc.calculate_weighted_score(my_scp_weight)
total_score += score
total_max_score += max_score
period += 1
if total_max_score > 0:
self.supplier_score = round(100.0 * (total_score / total_max_score) ,1)
else:
self.supplier_score = 100
def update_standing(self):
# Get the setup document
for standing in self.standings:
if (not standing.min_grade or (standing.min_grade <= self.supplier_score)) and \
(not standing.max_grade or (standing.max_grade > self.supplier_score)):
self.status = standing.standing_name
self.indicator_color = standing.standing_color
self.notify_supplier = standing.notify_supplier
self.notify_employee = standing.notify_employee
self.employee_link = standing.employee_link
#Update supplier standing info
for fieldname in ('prevent_pos', 'prevent_rfqs','warn_rfqs','warn_pos'):
self.set(fieldname, standing.get(fieldname))
frappe.db.set_value("Supplier", self.supplier, fieldname, self.get(fieldname))
@frappe.whitelist()
def get_timeline_data(doctype, name):
# Get a list of all the associated scorecards
scs = frappe.get_doc(doctype, name)
out = {}
timeline_data = {}
scorecards = frappe.db.sql("""
SELECT
sc.name
FROM
`tabSupplier Scorecard Period` sc
WHERE
sc.scorecard = %(scs)s""",
{"scs": scs.name}, as_dict=1)
for sc in scorecards:
start_date, end_date, total_score = frappe.db.get_value('Supplier Scorecard Period', sc.name, ['start_date', 'end_date', 'total_score'])
for single_date in daterange(start_date, end_date):
timeline_data[time.mktime(single_date.timetuple())] = total_score
out['timeline_data'] = timeline_data
return out
def daterange(start_date, end_date):
for n in range(int ((end_date - start_date).days)+1):
yield start_date + timedelta(n)
def refresh_scorecards():
scorecards = frappe.db.sql("""
SELECT
sc.name
FROM
`tabSupplier Scorecard` sc""",
{}, as_dict=1)
for sc in 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.whitelist()
def make_all_scorecards(docname):
sc = frappe.get_doc('Supplier Scorecard', docname)
supplier = frappe.get_doc('Supplier',sc.supplier)
start_date = getdate(supplier.creation)
end_date = get_scorecard_date(sc.period, start_date)
todays = getdate(nowdate())
scp_count = 0
first_start_date = todays
last_end_date = todays
while (start_date < todays) and (end_date <= todays):
# check to make sure there is no scorecard period already created
scorecards = frappe.db.sql("""
SELECT
scp.name
FROM
`tabSupplier Scorecard Period` scp
WHERE
scp.scorecard = %(sc)s
AND (
(scp.start_date > %(end_date)s
AND scp.end_date < %(start_date)s)
OR
(scp.start_date < %(end_date)s
AND scp.end_date > %(start_date)s))
ORDER BY
scp.end_date DESC""",
{"sc": docname, "start_date": start_date, "end_date": end_date, "supplier": supplier}, as_dict=1)
if len(scorecards) == 0:
period_card = make_supplier_scorecard(docname, None)
period_card.start_date = start_date
period_card.end_date = end_date
period_card.save()
scp_count = scp_count + 1
if start_date < first_start_date:
first_start_date = start_date
last_end_date = end_date
start_date = getdate(add_days(end_date,1))
end_date = get_scorecard_date(sc.period, start_date)
if scp_count > 0:
frappe.msgprint(_("Created {0} scorecards for {1} between: ").format(scp_count, sc.supplier) + str(first_start_date) + " - " + str(last_end_date))
return scp_count
def get_scorecard_date(period, start_date):
if period == 'Per Week':
end_date = getdate(add_days(start_date,7))
elif period == 'Per Month':
end_date = get_last_day(start_date)
elif period == 'Per Year':
end_date = add_days(add_years(start_date,1), -1)
return end_date
def make_default_records():
install_variable_docs = [
{"param_name": "total_accepted_items", "variable_label": "Total Accepted Items", \
"path": "get_total_accepted_items"},
{"param_name": "total_accepted_amount", "variable_label": "Total Accepted Amount", \
"path": "get_total_accepted_amount"},
{"param_name": "total_rejected_items", "variable_label": "Total Rejected Items", \
"path": "get_total_rejected_items"},
{"param_name": "total_rejected_amount", "variable_label": "Total Rejected Amount", \
"path": "get_total_rejected_amount"},
{"param_name": "total_received_items", "variable_label": "Total Received Items", \
"path": "get_total_received_items"},
{"param_name": "total_received_amount", "variable_label": "Total Received Amount", \
"path": "get_total_received_amount"},
{"param_name": "rfq_response_days", "variable_label": "RFQ Response Days", \
"path": "get_rfq_response_days"},
{"param_name": "sq_total_items", "variable_label": "SQ Total Items", \
"path": "get_sq_total_items"},
{"param_name": "sq_total_number", "variable_label": "SQ Total Number", \
"path": "get_sq_total_number"},
{"param_name": "rfq_total_number", "variable_label": "RFQ Total Number", \
"path": "get_rfq_total_number"},
{"param_name": "rfq_total_items", "variable_label": "RFQ Total Items", \
"path": "get_rfq_total_items"},
{"param_name": "tot_item_days", "variable_label": "Total Item Days", \
"path": "get_item_workdays"},
{"param_name": "on_time_shipment_num", "variable_label": "# of On Time Shipments", "path": \
"get_on_time_shipments"},
{"param_name": "cost_of_delayed_shipments", "variable_label": "Cost of Delayed Shipments", \
"path": "get_cost_of_delayed_shipments"},
{"param_name": "cost_of_on_time_shipments", "variable_label": "Cost of On Time Shipments", \
"path": "get_cost_of_on_time_shipments"},
{"param_name": "total_working_days", "variable_label": "Total Working Days", \
"path": "get_total_workdays"},
{"param_name": "tot_cost_shipments", "variable_label": "Total Cost of Shipments", \
"path": "get_total_cost_of_shipments"},
{"param_name": "tot_days_late", "variable_label": "Total Days Late", \
"path": "get_total_days_late"},
{"param_name": "total_shipments", "variable_label": "Total Shipments", \
"path": "get_total_shipments"}
]
install_standing_docs = [
{"min_grade": 0.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 30.0, "prevent_pos": 1, \
"standing_color": "Red", "notify_employee": 0, "standing_name": "Very Poor"},
{"min_grade": 30.0, "prevent_rfqs": 1, "notify_supplier": 0, "max_grade": 50.0, "prevent_pos": 0, \
"standing_color": "Red", "notify_employee": 0, "standing_name": "Poor"},
{"min_grade": 50.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 80.0, "prevent_pos": 0, \
"standing_color": "Green", "notify_employee": 0, "standing_name": "Average"},
{"min_grade": 80.0, "prevent_rfqs": 0, "notify_supplier": 0, "max_grade": 100.0, "prevent_pos": 0, \
"standing_color": "Blue", "notify_employee": 0, "standing_name": "Excellent"},
]
for d in install_variable_docs:
try:
d['doctype'] = "Supplier Scorecard Variable"
frappe.get_doc(d).insert()
except frappe.NameError:
pass
for d in install_standing_docs:
try:
d['doctype'] = "Supplier Scorecard Standing"
frappe.get_doc(d).insert()
except frappe.NameError:
pass

View File

@@ -0,0 +1,15 @@
from frappe import _
def get_data():
return {
'heatmap': True,
'heatmap_message': _('This covers all scorecards tied to this Setup'),
'fieldname': 'supplier',
'method' : 'erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.get_timeline_data',
'transactions': [
{
'label': _('Scorecards'),
'items': ['Supplier Scorecard Period']
}
]
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe, __ */
frappe.listview_settings["Supplier Scorecard"] = {
add_fields: ["indicator_color", "status"],
get_indicator: function(doc) {
if (doc.indicator_color) {
return [__(doc.status), doc.indicator_color.toLowerCase(), "status,=," + doc.status];
} else {
return [__("Unknown"), "darkgrey", "status,=,''"];
}
},
};

View File

@@ -0,0 +1,190 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestSupplierScorecard(unittest.TestCase):
def test_create_scorecard(self):
delete_test_scorecards()
my_doc = make_supplier_scorecard()
doc = my_doc.insert()
self.assertEqual(doc.name, valid_scorecard[0].get("supplier"))
def test_criteria_weight(self):
delete_test_scorecards()
my_doc = make_supplier_scorecard()
for d in my_doc.criteria:
d.weight = 0
self.assertRaises(frappe.ValidationError,my_doc.insert)
def test_missing_variable(self):
delete_test_scorecards()
my_doc = make_supplier_scorecard()
del my_doc.variables
self.assertRaises(frappe.ValidationError,my_doc.insert)
def make_supplier_scorecard():
my_doc = frappe.get_doc(valid_scorecard[0])
# Make sure the criteria exist (making them)
for d in valid_scorecard[0].get("criteria"):
if not frappe.db.exists("Supplier Scorecard Criteria", d.get("criteria_name")):
d["doctype"] = "Supplier Scorecard Criteria"
d["name"] = d.get("criteria_name")
my_criteria = frappe.get_doc(d)
my_criteria.insert()
return my_doc
def delete_test_scorecards():
my_doc = make_supplier_scorecard()
if frappe.db.exists("Supplier Scorecard", my_doc.name):
# Delete all the periods, then delete the scorecard
frappe.db.sql("""delete from `tabSupplier Scorecard Period` where scorecard = %(scorecard)s""", {'scorecard': my_doc.name})
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
frappe.delete_doc(my_doc.doctype, my_doc.name)
valid_scorecard = [
{
"standings":[
{
"min_grade":0.0,"name":"Very Poor",
"prevent_rfqs":1,
"notify_supplier":0,
"doctype":"Supplier Scorecard Standing",
"max_grade":30.0,
"prevent_pos":1,
"warn_pos":0,
"warn_rfqs":0,
"standing_color":"Red",
"notify_employee":0,
"standing_name":"Very Poor",
"parenttype":"Supplier Scorecard",
"parentfield":"standings"
},
{
"min_grade":30.0,
"name":"Poor",
"prevent_rfqs":1,
"notify_supplier":0,
"doctype":"Supplier Scorecard Standing",
"max_grade":50.0,
"prevent_pos":0,
"warn_pos":0,
"warn_rfqs":0,
"standing_color":"Red",
"notify_employee":0,
"standing_name":"Poor",
"parenttype":"Supplier Scorecard",
"parentfield":"standings"
},
{
"min_grade":50.0,
"name":"Average",
"prevent_rfqs":0,
"notify_supplier":0,
"doctype":"Supplier Scorecard Standing",
"max_grade":80.0,
"prevent_pos":0,
"warn_pos":0,
"warn_rfqs":0,
"standing_color":"Green",
"notify_employee":0,
"standing_name":"Average",
"parenttype":"Supplier Scorecard",
"parentfield":"standings"
},
{
"min_grade":80.0,
"name":"Excellent",
"prevent_rfqs":0,
"notify_supplier":0,
"doctype":"Supplier Scorecard Standing",
"max_grade":100.0,
"prevent_pos":0,
"warn_pos":0,
"warn_rfqs":0,
"standing_color":"Blue",
"notify_employee":0,
"standing_name":"Excellent",
"parenttype":"Supplier Scorecard",
"parentfield":"standings"
}
],
"prevent_pos":0,
"variables": [
{
"param_name":"cost_of_on_time_shipments",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"Cost of On Time Shipments",
"path":"get_cost_of_on_time_shipments",
"parentfield":"variables"
},
{
"param_name":"tot_cost_shipments",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"Total Cost of Shipments",
"path":"get_total_cost_of_shipments",
"parentfield":"variables"
},
{
"param_name":"tot_days_late",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"Total Days Late",
"path":"get_total_days_late",
"parentfield":"variables"
},
{
"param_name":"total_working_days",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"Total Working Days",
"path":"get_total_workdays",
"parentfield":"variables"
},
{
"param_name":"on_time_shipment_num",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"# of On Time Shipments",
"path":"get_on_time_shipments",
"parentfield":"variables"
},
{
"param_name":"total_shipments",
"doctype":"Supplier Scorecard Scoring Variable",
"parenttype":"Supplier Scorecard",
"variable_label":"Total Shipments",
"path":"get_total_shipments",
"parentfield":"variables"
}
],
"period":"Per Month",
"doctype":"Supplier Scorecard",
"warn_pos":0,
"warn_rfqs":0,
"notify_supplier":0,
"criteria":[
{
"weight":100.0,
"doctype":"Supplier Scorecard Scoring Criteria",
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100 ",
"criteria_name":"Delivery",
"max_score":100.0,
}
],
"supplier":"_Test Supplier",
"name":"_Test Supplier",
"weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )",
}
]

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe */
frappe.ui.form.on("Supplier Scorecard Criteria", {
refresh: function() {}
});

View File

@@ -0,0 +1,184 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:criteria_name",
"beta": 1,
"creation": "2017-05-29 01:32:43.064891",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "criteria_name",
"fieldtype": "Data",
"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": "Criteria Name",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "weight",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Criteria Weight",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "100",
"fieldname": "max_score",
"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": "Max Score",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "formula",
"fieldtype": "Small Text",
"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": "Criteria Formula",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-17 10:30:47.458285",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Criteria",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
import re
from frappe.model.document import Document
class InvalidFormulaVariable(frappe.ValidationError): pass
class SupplierScorecardCriteria(Document):
def validate(self):
self.validate_variables()
self.validate_formula()
def validate_variables(self):
# make sure all the variables exist
_get_variables(self)
def validate_formula(self):
# evaluate the formula with 0's to make sure it is valid
test_formula = self.formula.replace("\r", "").replace("\n", "")
regex = r"\{(.*?)\}"
mylist = re.finditer(regex, test_formula, re.MULTILINE | re.DOTALL)
for dummy1, match in enumerate(mylist):
for dummy2 in range(0, len(match.groups())):
test_formula = test_formula.replace('{' + match.group(1) + '}', "0")
test_formula = test_formula.replace('&lt;','<').replace('&gt;','>')
try:
frappe.safe_eval(test_formula, None, {'max':max, 'min': min})
except Exception:
frappe.throw(_("Error evaluating the criteria formula"))
@frappe.whitelist()
def get_scoring_criteria(criteria_name):
criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
return criteria
@frappe.whitelist()
def get_criteria_list():
criteria = frappe.db.sql("""
SELECT
scs.name
FROM
`tabSupplier Scorecard Criteria` scs""",
{}, as_dict=1)
return criteria
@frappe.whitelist()
def get_variables(criteria_name):
criteria = frappe.get_doc("Supplier Scorecard Criteria", criteria_name)
return _get_variables(criteria)
def _get_variables(criteria):
my_variables = []
regex = r"\{(.*?)\}"
mylist = re.finditer(regex, criteria.formula, re.MULTILINE | re.DOTALL)
for dummy1, match in enumerate(mylist):
for dummy2 in range(0, len(match.groups())):
try:
#var = frappe.get_doc("Supplier Scorecard Variable", {'param_name' : d})
var = frappe.db.sql("""
SELECT
scv.name
FROM
`tabSupplier Scorecard Variable` scv
WHERE
param_name=%(param)s""",
{'param':match.group(1)},)[0][0]
my_variables.append(var)
except Exception:
# Ignore the ones where the variable can't be found
frappe.throw(_('Unable to find variable: ') + str(match.group(1)), InvalidFormulaVariable)
#pass
#frappe.msgprint(str(my_variables))
return my_variables

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestSupplierScorecardCriteria(unittest.TestCase):
def test_variables_exist(self):
delete_test_scorecards()
for d in test_good_criteria:
frappe.get_doc(d).insert()
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[0]).insert)
def test_formula_validate(self):
delete_test_scorecards()
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[1]).insert)
self.assertRaises(frappe.ValidationError,frappe.get_doc(test_bad_criteria[2]).insert)
def delete_test_scorecards():
# Delete all the periods so we can delete all the criteria
frappe.db.sql("""delete from `tabSupplier Scorecard Period`""")
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Criteria` where parenttype = 'Supplier Scorecard Period'""")
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Standing` where parenttype = 'Supplier Scorecard Period'""")
frappe.db.sql("""delete from `tabSupplier Scorecard Scoring Variable` where parenttype = 'Supplier Scorecard Period'""")
for d in test_good_criteria:
if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
# Delete all the periods, then delete the scorecard
frappe.delete_doc(d.get("doctype"), d.get("name"))
for d in test_bad_criteria:
if frappe.db.exists("Supplier Scorecard Criteria", d.get("name")):
# Delete all the periods, then delete the scorecard
frappe.delete_doc(d.get("doctype"), d.get("name"))
test_good_criteria = [
{
"name":"Delivery",
"weight":40.0,
"doctype":"Supplier Scorecard Criteria",
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100",
"criteria_name":"Delivery",
"max_score":100.0
},
]
test_bad_criteria = [
{
"name":"Fake Criteria 1",
"weight":40.0,
"doctype":"Supplier Scorecard Criteria",
"formula":"(({fake_variable} / {tot_cost_shipments}) if {tot_cost_shipments} > 0 else 1 )* 100", # Invalid variable name
"criteria_name":"Fake Criteria 1",
"max_score":100.0
},
{
"name":"Fake Criteria 2",
"weight":40.0,
"doctype":"Supplier Scorecard Criteria",
"formula":"(({cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Force 0 divided by 0
"criteria_name":"Fake Criteria 2",
"max_score":100.0
},
{
"name":"Fake Criteria 3",
"weight":40.0,
"doctype":"Supplier Scorecard Criteria",
"formula":"(({cost_of_on_time_shipments} {cost_of_on_time_shipments} / {tot_cost_shipments}))* 100", # Two variables beside eachother
"criteria_name":"Fake Criteria 3",
"max_score":100.0
},
]

View File

@@ -0,0 +1,14 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe */
frappe.ui.form.on("Supplier Scorecard Period", {
onload: function(frm) {
frm.get_field("variables").grid.toggle_display("value", true);
frm.get_field("criteria").grid.toggle_display("score", true);
}
});

View File

@@ -0,0 +1,397 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "naming_series:",
"beta": 1,
"creation": "2017-05-30 00:38:18.773013",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Supplier",
"length": 0,
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "naming_series",
"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": "Naming Series",
"length": 0,
"no_copy": 0,
"options": "SSC-",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_score",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Period Score",
"length": 0,
"no_copy": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Start Date",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "end_date",
"fieldtype": "Date",
"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": "End Date",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "section_break_11",
"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": "Calculations",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "criteria",
"fieldtype": "Table",
"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": "Criteria",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Scoring Criteria",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "variables",
"fieldtype": "Table",
"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": "Variables",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Scoring Variable",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "sec_ref",
"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": "Reference",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "scorecard",
"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": "Supplier Scorecard Setup",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 1,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-12 07:33:26.130861",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Period",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import throw, _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
import erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable as variable_functions
class SupplierScorecardPeriod(Document):
def validate(self):
self.validate_criteria_weights()
self.calculate_variables()
self.calculate_criteria()
self.calculate_score()
def validate_criteria_weights(self):
weight = 0
for c in self.criteria:
weight += c.weight
if weight != 100:
throw(_('Criteria weights must add up to 100%'))
def calculate_variables(self):
for var in self.variables:
if '.' in var.path:
method_to_call = import_string_path(var.path)
var.value = method_to_call(self)
else:
method_to_call = getattr(variable_functions, var.path)
var.value = method_to_call(self)
def calculate_criteria(self):
#Get the criteria
for crit in self.criteria:
#me = ""
my_eval_statement = crit.formula.replace("\r", "").replace("\n", "")
#for let in my_eval_statement:
# me += let.encode('hex') + " "
#frappe.msgprint(me)
for var in self.variables:
if var.value:
if var.param_name in my_eval_statement:
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
else:
if var.param_name in my_eval_statement:
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
#frappe.msgprint(my_eval_statement )
my_eval_statement = my_eval_statement.replace('&lt;','<').replace('&gt;','>')
try:
crit.score = min(crit.max_score, max( 0 ,frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})))
except Exception:
frappe.throw(_("Could not solve criteria score function for {0}. Make sure the formula is valid.".format(crit.criteria_name)),frappe.ValidationError)
crit.score = 0
def calculate_score(self):
myscore = 0
for crit in self.criteria:
myscore += crit.score * crit.weight/100.0
self.total_score = myscore
def calculate_weighted_score(self, weighing_function):
my_eval_statement = weighing_function.replace("\r", "").replace("\n", "")
for var in self.variables:
if var.value:
if var.param_name in my_eval_statement:
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', "{:.2f}".format(var.value))
else:
if var.param_name in my_eval_statement:
my_eval_statement = my_eval_statement.replace('{' + var.param_name + '}', '0.0')
my_eval_statement = my_eval_statement.replace('&lt;','<').replace('&gt;','>')
try:
weighed_score = frappe.safe_eval(my_eval_statement, None, {'max':max, 'min': min})
except Exception:
frappe.throw(_("Could not solve weighted score function. Make sure the formula is valid."),frappe.ValidationError)
weighed_score = 0
return weighed_score
def import_string_path(path):
components = path.split('.')
mod = __import__(components[0])
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
def post_process(source, target):
pass
@frappe.whitelist()
def make_supplier_scorecard(source_name, target_doc=None):
#def update_item(obj, target, source_parent):
# target.qty = flt(obj.qty) - flt(obj.received_qty)
# target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
# target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
# target.base_amount = (flt(obj.qty) - flt(obj.received_qty)) * \
# flt(obj.rate) * flt(source_parent.conversion_rate)
doc = get_mapped_doc("Supplier Scorecard", source_name, {
"Supplier Scorecard": {
"doctype": "Supplier Scorecard Period"
},
"Supplier Scorecard Scoring Variable": {
"doctype": "Supplier Scorecard Scoring Variable",
"add_if_empty": True
},
"Supplier Scorecard Scoring Constraint": {
"doctype": "Supplier Scorecard Scoring Constraint",
"add_if_empty": True
}
}, target_doc, post_process)
return doc

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestSupplierScorecardPeriod(unittest.TestCase):
pass

View File

@@ -0,0 +1,280 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1,
"creation": "2017-05-29 01:32:17.988454",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "criteria_name",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Criteria Name",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Criteria",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "weight",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Criteria Weight",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "100",
"fieldname": "max_score",
"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": "Max Score",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "formula",
"fieldtype": "Small Text",
"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": "Criteria Formula",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "score",
"fieldtype": "Percent",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Score",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-07-12 07:33:41.532361",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Scoring Criteria",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class SupplierScorecardScoringCriteria(Document):
pass

View File

@@ -0,0 +1,491 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1,
"creation": "2017-05-29 01:36:22.697234",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "standing_name",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Standing Name",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Standing",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "standing_color",
"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": "Color",
"length": 0,
"no_copy": 0,
"options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_4",
"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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "min_grade",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Min Grade",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "max_grade",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Max Grade",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actions",
"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": "Actions",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_rfqs",
"fieldtype": "Check",
"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": "Warn RFQs",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_pos",
"fieldtype": "Check",
"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": "Warn Purchase Orders",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_rfqs",
"fieldtype": "Check",
"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": "Prevent RFQs",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_pos",
"fieldtype": "Check",
"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": "Prevent Purchase Orders",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_10",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_supplier",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Supplier",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_employee",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Employee",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "employee_link",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee ",
"length": 0,
"no_copy": 0,
"options": "Employee",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-07-12 07:33:20.615684",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Scoring Standing",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class SupplierScorecardScoringStanding(Document):
pass

View File

@@ -0,0 +1,222 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1,
"creation": "2017-05-29 01:30:06.105240",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "variable_label",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Variable Name",
"length": 0,
"no_copy": 0,
"options": "Supplier Scorecard Variable",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_custom",
"fieldtype": "Check",
"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": "Custom?",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "param_name",
"fieldtype": "Data",
"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": "Parameter Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "path",
"fieldtype": "Data",
"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": "Path",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "value",
"fieldtype": "Float",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Value",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-07-12 07:33:36.671502",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Scoring Variable",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class SupplierScorecardScoringVariable(Document):
pass

View File

@@ -0,0 +1,10 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe */
frappe.ui.form.on("Supplier Scorecard Standing", {
refresh: function() {
}
});

View File

@@ -0,0 +1,424 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:standing_name",
"beta": 1,
"creation": "2017-05-29 01:36:47.893639",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "standing_name",
"fieldtype": "Data",
"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": "Standing Name",
"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,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "standing_color",
"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": "Color",
"length": 0,
"no_copy": 0,
"options": "Blue\nPurple\nGreen\nYellow\nOrange\nRed",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "min_grade",
"fieldtype": "Percent",
"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": "Min Grade",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "max_grade",
"fieldtype": "Percent",
"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": "Max Grade",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_rfqs",
"fieldtype": "Check",
"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": "Warn RFQs",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warn_pos",
"fieldtype": "Check",
"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": "Warn Purchase Orders",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_rfqs",
"fieldtype": "Check",
"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": "Prevent RFQs",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevent_pos",
"fieldtype": "Check",
"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": "Prevent Purchase Orders",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_supplier",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Supplier",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_employee",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify Other",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "employee_link",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Other",
"length": 0,
"no_copy": 0,
"options": "Employee",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-12 07:33:16.560273",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Standing",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class SupplierScorecardStanding(Document):
pass
@frappe.whitelist()
def get_scoring_standing(standing_name):
standing = frappe.get_doc("Supplier Scorecard Standing", standing_name)
return standing
@frappe.whitelist()
def get_standings_list():
standings = frappe.db.sql("""
SELECT
scs.name
FROM
`tabSupplier Scorecard Standing` scs""",
{}, as_dict=1)
return standings

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestSupplierScorecardStanding(unittest.TestCase):
pass

View File

@@ -0,0 +1,10 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* global frappe */
frappe.ui.form.on("Supplier Scorecard Variable", {
refresh: function() {
}
});

View File

@@ -0,0 +1,242 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:variable_label",
"beta": 1,
"creation": "2017-05-29 01:30:34.688389",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "variable_label",
"fieldtype": "Data",
"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": "Variable Name",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_custom",
"fieldtype": "Check",
"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": "Custom?",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "param_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Parameter Name",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "path",
"fieldtype": "Data",
"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": "Path",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5",
"fieldtype": "Column 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,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"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,
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-12 07:33:31.395262",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Scorecard Variable",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,503 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import sys
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate
class VariablePathNotFound(frappe.ValidationError): pass
class SupplierScorecardVariable(Document):
def validate(self):
self.validate_path_exists()
def validate_path_exists(self):
if '.' in self.path:
try:
from erpnext.buying.doctype.supplier_scorecard_period.supplier_scorecard_period import import_string_path
import_string_path(self.path)
except AttributeError:
frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
else:
if not hasattr(sys.modules[__name__], self.path):
frappe.throw(_("Could not find path for " + self.path), VariablePathNotFound)
@frappe.whitelist()
def get_scoring_variable(variable_label):
variable = frappe.get_doc("Supplier Scorecard Variable", variable_label)
return variable
def get_total_workdays(scorecard):
""" Gets the number of days in this period"""
delta = getdate(scorecard.end_date) - getdate(scorecard.start_date)
return delta.days
def get_item_workdays(scorecard):
""" Gets the number of days in this period"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
total_item_days = frappe.db.sql("""
SELECT
SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty))
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Order` po
WHERE
po.supplier = %(supplier)s
AND po_item.received_qty < po_item.qty
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.parent = po.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not total_item_days:
total_item_days = 0
return total_item_days
def get_total_cost_of_shipments(scorecard):
""" Gets the total cost of all shipments in the period (based on Purchase Orders)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(po_item.base_amount)
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Order` po
WHERE
po.supplier = %(supplier)s
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.docstatus = 1
AND po_item.parent = po.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if data:
return data
else:
return 0
def get_cost_of_delayed_shipments(scorecard):
""" Gets the total cost of all delayed shipments in the period (based on Purchase Receipts - POs)"""
return get_total_cost_of_shipments(scorecard) - get_cost_of_on_time_shipments(scorecard)
def get_cost_of_on_time_shipments(scorecard):
""" Gets the total cost of all on_time shipments in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
total_delivered_on_time_costs = frappe.db.sql("""
SELECT
SUM(pr_item.base_amount)
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Receipt Item` pr_item,
`tabPurchase Order` po,
`tabPurchase Receipt` pr
WHERE
po.supplier = %(supplier)s
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.schedule_date >= pr.posting_date
AND pr_item.docstatus = 1
AND pr_item.purchase_order_item = po_item.name
AND po_item.parent = po.name
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if total_delivered_on_time_costs:
return total_delivered_on_time_costs
else:
return 0
def get_total_days_late(scorecard):
""" Gets the number of item days late in the period (based on Purchase Receipts vs POs)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
total_delivered_late_days = frappe.db.sql("""
SELECT
SUM(DATEDIFF(pr.posting_date,po_item.schedule_date)* pr_item.qty)
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Receipt Item` pr_item,
`tabPurchase Order` po,
`tabPurchase Receipt` pr
WHERE
po.supplier = %(supplier)s
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.schedule_date < pr.posting_date
AND pr_item.docstatus = 1
AND pr_item.purchase_order_item = po_item.name
AND po_item.parent = po.name
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not total_delivered_late_days:
total_delivered_late_days = 0
total_missed_late_days = frappe.db.sql("""
SELECT
SUM(DATEDIFF( %(end_date)s, po_item.schedule_date) * (po_item.qty - po_item.received_qty))
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Order` po
WHERE
po.supplier = %(supplier)s
AND po_item.received_qty < po_item.qty
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.parent = po.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not total_missed_late_days:
total_missed_late_days = 0
return total_missed_late_days + total_delivered_late_days
def get_on_time_shipments(scorecard):
""" Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
total_items_delivered_on_time = frappe.db.sql("""
SELECT
COUNT(pr_item.qty)
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Receipt Item` pr_item,
`tabPurchase Order` po,
`tabPurchase Receipt` pr
WHERE
po.supplier = %(supplier)s
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.schedule_date <= pr.posting_date
AND po_item.qty = pr_item.qty
AND pr_item.docstatus = 1
AND pr_item.purchase_order_item = po_item.name
AND po_item.parent = po.name
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not total_items_delivered_on_time:
total_items_delivered_on_time = 0
return total_items_delivered_on_time
def get_late_shipments(scorecard):
""" Gets the number of late shipments (counting each item) in the period (based on Purchase Receipts vs POs)"""
return get_total_shipments(scorecard) - get_on_time_shipments(scorecard)
def get_total_received(scorecard):
""" Gets the total number of received shipments in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(pr_item.base_amount)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_received_amount(scorecard):
""" Gets the total amount (in company currency) received in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.received_qty * pr_item.base_rate)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_received_items(scorecard):
""" Gets the total number of received shipments in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.received_qty)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_rejected_amount(scorecard):
""" Gets the total amount (in company currency) rejected in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.rejected_qty * pr_item.base_rate)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_rejected_items(scorecard):
""" Gets the total number of rejected items in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.rejected_qty)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_accepted_amount(scorecard):
""" Gets the total amount (in company currency) accepted in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.qty * pr_item.base_rate)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_accepted_items(scorecard):
""" Gets the total number of rejected items in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
SUM(pr_item.qty)
FROM
`tabPurchase Receipt Item` pr_item,
`tabPurchase Receipt` pr
WHERE
pr.supplier = %(supplier)s
AND pr.posting_date BETWEEN %(start_date)s AND %(end_date)s
AND pr_item.docstatus = 1
AND pr_item.parent = pr.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_total_shipments(scorecard):
""" Gets the total number of ordered shipments to arrive in the period (based on Purchase Receipts)"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(po_item.base_amount)
FROM
`tabPurchase Order Item` po_item,
`tabPurchase Order` po
WHERE
po.supplier = %(supplier)s
AND po_item.schedule_date BETWEEN %(start_date)s AND %(end_date)s
AND po_item.docstatus = 1
AND po_item.parent = po.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_rfq_total_number(scorecard):
""" Gets the total number of RFQs sent to supplier"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(rfq.name) as total_rfqs
FROM
`tabRequest for Quotation Item` rfq_item,
`tabRequest for Quotation Supplier` rfq_sup,
`tabRequest for Quotation` rfq
WHERE
rfq_sup.supplier = %(supplier)s
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
AND rfq_item.docstatus = 1
AND rfq_item.parent = rfq.name
AND rfq_sup.parent = rfq.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_rfq_total_items(scorecard):
""" Gets the total number of RFQ items sent to supplier"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(rfq_item.name) as total_rfqs
FROM
`tabRequest for Quotation Item` rfq_item,
`tabRequest for Quotation Supplier` rfq_sup,
`tabRequest for Quotation` rfq
WHERE
rfq_sup.supplier = %(supplier)s
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
AND rfq_item.docstatus = 1
AND rfq_item.parent = rfq.name
AND rfq_sup.parent = rfq.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_sq_total_number(scorecard):
""" Gets the total number of RFQ items sent to supplier"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(sq.name) as total_sqs
FROM
`tabRequest for Quotation Item` rfq_item,
`tabSupplier Quotation Item` sq_item,
`tabRequest for Quotation Supplier` rfq_sup,
`tabRequest for Quotation` rfq,
`tabSupplier Quotation` sq
WHERE
rfq_sup.supplier = %(supplier)s
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
AND sq_item.request_for_quotation_item = rfq_item.name
AND sq_item.docstatus = 1
AND rfq_item.docstatus = 1
AND sq.supplier = %(supplier)s
AND sq_item.parent = sq.name
AND rfq_item.parent = rfq.name
AND rfq_sup.parent = rfq.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_sq_total_items(scorecard):
""" Gets the total number of RFQ items sent to supplier"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
# Look up all PO Items with delivery dates between our dates
data = frappe.db.sql("""
SELECT
COUNT(sq_item.name) as total_sqs
FROM
`tabRequest for Quotation Item` rfq_item,
`tabSupplier Quotation Item` sq_item,
`tabSupplier Quotation` sq,
`tabRequest for Quotation Supplier` rfq_sup,
`tabRequest for Quotation` rfq
WHERE
rfq_sup.supplier = %(supplier)s
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
AND sq_item.request_for_quotation_item = rfq_item.name
AND sq_item.docstatus = 1
AND sq.supplier = %(supplier)s
AND sq_item.parent = sq.name
AND rfq_item.docstatus = 1
AND rfq_item.parent = rfq.name
AND rfq_sup.parent = rfq.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not data:
data = 0
return data
def get_rfq_response_days(scorecard):
""" Gets the total number of days it has taken a supplier to respond to rfqs in the period"""
supplier = frappe.get_doc('Supplier', scorecard.supplier)
total_sq_days = frappe.db.sql("""
SELECT
SUM(DATEDIFF(sq.transaction_date, rfq.transaction_date))
FROM
`tabRequest for Quotation Item` rfq_item,
`tabSupplier Quotation Item` sq_item,
`tabSupplier Quotation` sq,
`tabRequest for Quotation Supplier` rfq_sup,
`tabRequest for Quotation` rfq
WHERE
rfq_sup.supplier = %(supplier)s
AND rfq.transaction_date BETWEEN %(start_date)s AND %(end_date)s
AND sq_item.request_for_quotation_item = rfq_item.name
AND sq_item.docstatus = 1
AND sq.supplier = %(supplier)s
AND sq_item.parent = sq.name
AND rfq_item.docstatus = 1
AND rfq_item.parent = rfq.name
AND rfq_sup.parent = rfq.name""",
{"supplier": supplier.name, "start_date": scorecard.start_date, "end_date": scorecard.end_date}, as_dict=0)[0][0]
if not total_sq_days:
total_sq_days = 0
return total_sq_days

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import VariablePathNotFound
class TestSupplierScorecardVariable(unittest.TestCase):
def test_variable_exist(self):
for d in test_existing_variables:
my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name"))
self.assertEquals(my_doc.param_name, d.get('param_name'))
self.assertEquals(my_doc.variable_label, d.get('variable_label'))
self.assertEquals(my_doc.path, d.get('path'))
def test_path_exists(self):
for d in test_good_variables:
if frappe.db.exists(d):
frappe.delete_doc(d.get("doctype"), d.get("name"))
frappe.get_doc(d).insert()
for d in test_bad_variables:
self.assertRaises(VariablePathNotFound,frappe.get_doc(d).insert)
test_existing_variables = [
{
"param_name":"total_accepted_items",
"name":"Total Accepted Items",
"doctype":"Supplier Scorecard Variable",
"variable_label":"Total Accepted Items",
"path":"get_total_accepted_items"
},
]
test_good_variables = [
{
"param_name":"good_variable1",
"name":"Good Variable 1",
"doctype":"Supplier Scorecard Variable",
"variable_label":"Good Variable 1",
"path":"get_total_accepted_items"
},
]
test_bad_variables = [
{
"param_name":"fake_variable1",
"name":"Fake Variable 1",
"doctype":"Supplier Scorecard Variable",
"variable_label":"Fake Variable 1",
"path":"get_fake_variable1"
},
]

View File

@@ -141,6 +141,32 @@ def get_data():
},
]
},
{
"label": _("Supplier Scorecard"),
"items": [
{
"type": "doctype",
"name": "Supplier Scorecard",
"description": _("All Supplier scorecards."),
},
{
"type": "doctype",
"name": "Supplier Scorecard Variable",
"description": _("Templates of supplier scorecard variables.")
},
{
"type": "doctype",
"name": "Supplier Scorecard Criteria",
"description": _("Templates of supplier scorecard criteria."),
},
{
"type": "doctype",
"name": "Supplier Scorecard Standing",
"description": _("Templates of supplier standings."),
},
]
},
{
"label": _("Other Reports"),
"icon": "fa fa-list",

View File

@@ -17,6 +17,11 @@ def get_data():
"name": "Task",
"description": _("Project activity / task."),
},
{
"type": "doctype",
"name": "Project Type",
"description": _("Define Project type."),
},
{
"type": "report",
"route": "List/Task/Gantt",

View File

@@ -160,6 +160,7 @@ class AccountsController(TransactionBase):
def set_missing_item_details(self, for_validate=False):
"""set missing item values"""
from erpnext.stock.get_item_details import get_item_details
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
if hasattr(self, "items"):
parent_dict = {}
@@ -196,7 +197,7 @@ class AccountsController(TransactionBase):
elif fieldname == "serial_no":
stock_qty = item.get("stock_qty") * -1 if item.get("stock_qty") < 0 else item.get("stock_qty")
if stock_qty != len(item.get('serial_no').split('\n')):
if stock_qty != len(get_serial_nos(item.get('serial_no'))):
item.set(fieldname, value)
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):

View File

@@ -169,7 +169,6 @@ def create_variant(item, args):
return variant
def copy_attributes_to_variant(item, variant):
from frappe.model import no_value_fields
@@ -189,6 +188,8 @@ def copy_attributes_to_variant(item, variant):
variant.set(field.fieldname, item.get(field.fieldname))
variant.variant_of = item.name
variant.has_variants = 0
if not variant.description:
variant.description = ''
if item.variant_based_on=='Item Attribute':
if variant.attributes:

View File

@@ -60,6 +60,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
# searches for customer
def customer_query(doctype, txt, searchfield, start, page_len, filters):
conditions = []
cust_master_name = frappe.defaults.get_user_default("cust_master_name")
if cust_master_name == "Customer Name":
@@ -79,7 +80,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select {fields} from `tabCustomer`
where docstatus < 2
and ({scond}) and disabled=0
{mcond}
{fcond} {mcond}
order by
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999),
@@ -88,7 +89,8 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
limit %(start)s, %(page_len)s""".format(**{
"fields": fields,
"scond": searchfields,
"mcond": get_match_cond(doctype)
"mcond": get_match_cond(doctype),
"fcond": get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
}), {
'txt': "%%%s%%" % txt,
'_txt': txt.replace("%", ""),

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import json
import frappe, erpnext
from frappe import _, scrub
from frappe.utils import cint, flt, cstr, fmt_money, round_based_on_smallest_currency_fraction
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax
@@ -509,103 +509,75 @@ class calculate_taxes_and_totals(object):
return rate_with_margin
def set_item_wise_tax_breakup(self):
item_tax = {}
tax_accounts = []
company_currency = erpnext.get_company_currency(self.doc.company)
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts, company_currency)
headings = get_table_column_headings(tax_accounts)
distinct_items = self.get_distinct_items()
rows = get_table_rows(distinct_items, item_tax, tax_accounts, company_currency)
if not rows:
self.doc.other_charges_calculation = ""
else:
self.doc.other_charges_calculation = '''
<div class="tax-break-up" style="overflow-x: auto;">
<table class="table table-bordered table-hover">
<thead><tr>{headings}</tr></thead>
<tbody>{rows}</tbody>
</table>
</div>'''.format(**{
"headings": "".join(headings),
"rows": "".join(rows)
})
def get_item_tax(self, item_tax, tax_accounts, company_currency):
for tax in self.doc.taxes:
tax_amount_precision = tax.precision("tax_amount")
tax_rate_precision = tax.precision("rate");
item_tax_map = self._load_item_tax_rate(tax.item_wise_tax_detail)
for item_code, tax_data in item_tax_map.items():
if not item_tax.get(item_code):
item_tax[item_code] = {}
if isinstance(tax_data, list):
tax_rate = ""
if tax_data[0]:
if tax.charge_type == "Actual":
tax_rate = fmt_money(flt(tax_data[0], tax_amount_precision),
tax_amount_precision, company_currency)
else:
tax_rate = cstr(flt(tax_data[0], tax_rate_precision)) + "%"
tax_amount = fmt_money(flt(tax_data[1], tax_amount_precision),
tax_amount_precision, company_currency)
item_tax[item_code][tax.name] = [tax_rate, tax_amount]
else:
item_tax[item_code][tax.name] = [cstr(flt(tax_data, tax_rate_precision)) + "%", ""]
tax_accounts.append([tax.name, tax.account_head])
return item_tax, tax_accounts
def get_itemised_tax_breakup_html(doc):
if not doc.taxes:
return
frappe.flags.company = doc.company
def get_distinct_items(self):
distinct_item_names = []
distinct_items = []
for item in self.doc.items:
item_code = item.item_code or item.item_name
if item_code not in distinct_item_names:
distinct_item_names.append(item_code)
distinct_items.append(item)
return distinct_items
# get headers
tax_accounts = list(set([d.description for d in doc.taxes]))
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
# get tax breakup data
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
frappe.flags.company = None
return frappe.render_template(
"templates/includes/itemised_tax_breakup.html", dict(
headers=headers,
itemised_tax=itemised_tax,
itemised_taxable_amount=itemised_taxable_amount,
tax_accounts=tax_accounts,
company_currency=erpnext.get_company_currency(doc.company)
)
)
def get_table_column_headings(tax_accounts):
headings_name = [_("Item Name"), _("Taxable Amount")] + [d[1] for d in tax_accounts]
headings = []
for head in headings_name:
if head == _("Item Name"):
headings.append('<th style="min-width: 120px;" class="text-left">' + (head or "") + "</th>")
else:
headings.append('<th style="min-width: 80px;" class="text-right">' + (head or "") + "</th>")
@erpnext.allow_regional
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
return [_("Item"), _("Taxable Amount")] + tax_accounts
@erpnext.allow_regional
def get_itemised_tax_breakup_data(doc):
itemised_tax = get_itemised_tax(doc.taxes)
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
return itemised_tax, itemised_taxable_amount
def get_itemised_tax(taxes):
itemised_tax = {}
for tax in taxes:
tax_amount_precision = tax.precision("tax_amount")
tax_rate_precision = tax.precision("rate")
item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
for item_code, tax_data in item_tax_map.items():
itemised_tax.setdefault(item_code, frappe._dict())
return headings
def get_table_rows(distinct_items, item_tax, tax_accounts, company_currency):
rows = []
for item in distinct_items:
item_tax_record = item_tax.get(item.item_code or item.item_name)
if not item_tax_record:
continue
taxes = []
for head in tax_accounts:
if item_tax_record[head[0]]:
taxes.append("<td class='text-right'>(" + item_tax_record[head[0]][0] + ") "
+ item_tax_record[head[0]][1] + "</td>")
if isinstance(tax_data, list) and tax_data[0]:
precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data[0], precision),
tax_amount=flt(tax_data[1], tax_amount_precision)
))
else:
taxes.append("<td></td>")
rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
"item_name": item.item_name,
"taxable_amount": fmt_money(item.net_amount, item.precision("net_amount"), company_currency),
"taxes": "".join(taxes)
}))
return rows
itemised_tax[item_code][tax.description] = frappe._dict(dict(
tax_rate=flt(tax_data, tax_rate_precision),
tax_amount=0.0
))
return itemised_tax
def get_itemised_taxable_amount(items):
itemised_taxable_amount = frappe._dict()
for item in items:
item_code = item.item_code or item.item_name
itemised_taxable_amount.setdefault(item_code, 0)
itemised_taxable_amount[item_code] += item.net_amount
return itemised_taxable_amount

View File

@@ -30,7 +30,7 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p
else:
filters.append((doctype, "docstatus", "=", 1))
if user != "Guest" and is_website_user():
if (user != "Guest" and is_website_user()) or doctype == 'Request for Quotation':
parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype
# find party for this contact
customers, suppliers = get_customers_suppliers(parties_doctype, user)

View File

@@ -0,0 +1,82 @@
QUnit.test("test: item", function (assert) {
assert.expect(6);
let done = assert.async();
let keyboard_cost = 800;
let screen_cost = 4000;
let CPU_cost = 15000;
let scrap_cost = 100;
let no_of_items_to_stock = 100;
let is_stock_item = 1;
frappe.run_serially([
// test item creation
() => frappe.set_route("List", "Item"),
// Create a keyboard item
() => frappe.tests.make(
"Item", [
{item_code: "Keyboard"},
{item_group: "Products"},
{is_stock_item: is_stock_item},
{standard_rate: keyboard_cost},
{opening_stock: no_of_items_to_stock}
]
),
() => {
assert.ok(cur_frm.doc.item_name.includes('Keyboard'),
'Item Keyboard created correctly');
assert.ok(cur_frm.doc.item_code.includes('Keyboard'),
'item_code for Keyboard set correctly');
assert.ok(cur_frm.doc.item_group.includes('Products'),
'item_group for Keyboard set correctly');
assert.equal(cur_frm.doc.is_stock_item, is_stock_item,
'is_stock_item for Keyboard set correctly');
assert.equal(cur_frm.doc.standard_rate, keyboard_cost,
'standard_rate for Keyboard set correctly');
assert.equal(cur_frm.doc.opening_stock, no_of_items_to_stock,
'opening_stock for Keyboard set correctly');
},
// Create a Screen item
() => frappe.tests.make(
"Item", [
{item_code: "Screen"},
{item_group: "Products"},
{is_stock_item: is_stock_item},
{standard_rate: screen_cost},
{opening_stock: no_of_items_to_stock}
]
),
// Create a CPU item
() => frappe.tests.make(
"Item", [
{item_code: "CPU"},
{item_group: "Products"},
{is_stock_item: is_stock_item},
{standard_rate: CPU_cost},
{opening_stock: no_of_items_to_stock}
]
),
// Create a laptop item
() => frappe.tests.make(
"Item", [
{item_code: "Laptop"},
{item_group: "Products"}
]
),
// Create a scrap item
() => frappe.tests.make(
"Item", [
{item_code: "Scrap item"},
{item_group: "Products"},
{is_stock_item: is_stock_item},
{standard_rate: scrap_cost},
{opening_stock: no_of_items_to_stock}
]
),
() => done()
]);
});

View File

@@ -0,0 +1,43 @@
QUnit.module("sales");
QUnit.test("test: lead", function (assert) {
assert.expect(4);
let done = assert.async();
let lead_name = frappe.utils.get_random(10);
frappe.run_serially([
// test lead creation
() => frappe.set_route("List", "Lead"),
() => frappe.new_doc("Lead"),
() => frappe.timeout(1),
() => cur_frm.set_value("lead_name", lead_name),
() => cur_frm.save(),
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.doc.lead_name.includes(lead_name),
'name correctly set');
frappe.lead_name = cur_frm.doc.name;
},
// create address and contact
() => frappe.click_link('Address & Contact'),
() => frappe.click_button('New Address'),
() => frappe.timeout(1),
() => frappe.set_control('address_line1', 'Gateway'),
() => frappe.set_control('city', 'Mumbai'),
() => cur_frm.save(),
() => frappe.timeout(3),
() => assert.equal(frappe.get_route()[1], 'Lead',
'back to lead form'),
() => frappe.click_link('Address & Contact'),
() => assert.ok($('.address-box').text().includes('Mumbai'),
'city is seen in address box'),
// make opportunity
() => frappe.click_button('Make'),
() => frappe.click_link('Opportunity'),
() => frappe.timeout(2),
() => assert.equal(cur_frm.doc.lead, frappe.lead_name,
'lead name correctly mapped'),
() => done()
]);
});

View File

@@ -56,7 +56,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
@@ -88,7 +88,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Opportunity From",
"length": 0,
@@ -277,8 +277,8 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Opportunity Type",
"length": 0,
"no_copy": 0,
@@ -310,7 +310,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
"length": 0,
@@ -1189,7 +1189,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:07.077697",
"modified": "2017-07-10 15:29:23.921967",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",

View File

@@ -272,4 +272,6 @@ def auto_close_opportunity():
for opportunity in opportunities:
doc = frappe.get_doc("Opportunity", opportunity.get("name"))
doc.status = "Closed"
doc.save(ignore_permissions=True)
doc.flags.ignore_permissions = True
doc.flags.ignore_mandatory = True
doc.save()

View File

@@ -0,0 +1,56 @@
QUnit.test("test: opportunity", function (assert) {
assert.expect(8);
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('List', 'Opportunity'),
() => frappe.timeout(1),
() => frappe.click_button('New'),
() => frappe.timeout(1),
() => cur_frm.set_value('enquiry_from', 'Customer'),
() => cur_frm.set_value('customer', 'Test Customer 1'),
// check items
() => cur_frm.set_value('with_items', 1),
() => frappe.tests.set_grid_values(cur_frm, 'items', [
[
{item_code:'Test Product 1'},
{qty: 4}
]
]),
() => cur_frm.save(),
() => frappe.timeout(1),
() => {
assert.notOk(cur_frm.is_new(), 'saved');
frappe.opportunity_name = cur_frm.doc.name;
},
// close and re-open
() => frappe.click_button('Close'),
() => frappe.timeout(1),
() => assert.equal(cur_frm.doc.status, 'Closed',
'closed'),
() => frappe.click_button('Reopen'),
() => assert.equal(cur_frm.doc.status, 'Open',
'reopened'),
() => frappe.timeout(1),
// make quotation
() => frappe.click_button('Make'),
() => frappe.click_link('Quotation', 1),
() => frappe.timeout(2),
() => {
assert.equal(frappe.get_route()[1], 'Quotation',
'made quotation');
assert.equal(cur_frm.doc.customer, 'Test Customer 1',
'customer set in quotation');
assert.equal(cur_frm.doc.items[0].item_code, 'Test Product 1',
'item set in quotation');
assert.equal(cur_frm.doc.items[0].qty, 4,
'qty set in quotation');
assert.equal(cur_frm.doc.items[0].prevdoc_docname, frappe.opportunity_name,
'opportunity set in quotation');
},
() => done()
]);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 443 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -640,8 +640,8 @@ attach them to the start of each source file to most effectively state
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.</p>
<pre><code> &lt;one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.=""&gt;
Copyright (C) &lt;year&gt; &lt;name of="" author=""&gt;
<pre><code> &lt;one line to give the program's name and a brief idea of what it does.&gt;
Copyright (C) &lt;year&gt; &lt;name of author&gt;
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

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