Compare commits

...

379 Commits

Author SHA1 Message Date
Nabin Hait
7e8d7d05ef Merge branch 'develop' 2015-07-27 15:55:57 +05:30
Nabin Hait
228ff87ea2 bumped to version 5.3.0 2015-07-27 16:25:56 +06:00
Nabin Hait
8d8655e1cd Change log added 2015-07-27 15:54:39 +05:30
Anand Doshi
14859faf17 [minor] Accounts Payable Report Type='Script Report' 2015-07-24 17:30:39 +05:30
Nabin Hait
2b7eda8135 Merge pull request #3683 from nabinhait/return
Sales / Purchase Return Enhancement
2015-07-24 16:53:01 +05:30
Anand Doshi
751d7ecd85 Merge pull request #3716 from tmimori/develop
Removed HTML from messages
2015-07-24 14:28:59 +05:30
Nabin Hait
6a09b3f7ef Merge pull request #3702 from neilLasrado/capacity-planning
Global switch to set capacity planning in manufacturing
2015-07-24 14:26:28 +05:30
Nabin Hait
21897e3c52 Merge pull request #3714 from nabinhait/fix4
[fix] gross profit report
2015-07-24 14:25:35 +05:30
Nabin Hait
15b4f6310c Merge pull request #3701 from neilLasrado/po
Disallowed End of Life Items from getting selected in Production Orders and Stock Reconciliation
2015-07-24 14:25:13 +05:30
Tsutomu Mimori
196a0bc675 Amend for frappe/erpnext/pull/3716 2015-07-24 17:06:00 +09:00
Tsutomu Mimori
7c011985f0 Merge remote-tracking branch 'frappe/develop' into develop 2015-07-24 17:02:13 +09:00
Nabin Hait
3cf67a462b Cleanup and test cases for serialized item 2015-07-24 13:26:54 +05:30
Nabin Hait
f061877b4f [fix] Stock Entry permissions 2015-07-24 13:26:54 +05:30
Nabin Hait
04d244a360 Credit Note print format 2015-07-24 13:26:54 +05:30
Nabin Hait
b74999da82 [testcase] Testcase for return purchase invoice 2015-07-24 13:26:53 +05:30
Nabin Hait
061f7079ed Test case for purchase return 2015-07-24 13:26:53 +05:30
Nabin Hait
246ed3f122 Test cases for sales return 2015-07-24 13:26:53 +05:30
Nabin Hait
6b25708b7a Minor fixes 2015-07-24 13:26:53 +05:30
Nabin Hait
623ed57663 Removed Sales/Purchase Return option from Stock Entry 2015-07-24 13:26:53 +05:30
Nabin Hait
1d21842f68 Sales / Purchase Return redesigned via negative DN / SI / PR / PI 2015-07-24 13:26:53 +05:30
Nabin Hait
ada485f096 Outgoing rate in Purchase Return based on reference/original Purchase Receipt rate 2015-07-24 13:26:53 +05:30
Neil Trini Lasrado
8a9d41a92e Modified Test Cases for Production Order 2015-07-24 13:18:45 +05:30
Neil Trini Lasrado
f965c5d203 now_datetime changed to nowdate 2015-07-24 13:14:57 +05:30
Neil Trini Lasrado
21647974c4 Test Cases Added to Production Order 2015-07-24 13:14:57 +05:30
Neil Trini Lasrado
9c3dca63fa Disallowed End of Life Items from getting selected in Production Orders and Stock Reconciliation 2015-07-24 13:14:56 +05:30
Tsutomu Mimori
c40b99be26 Merge remote-tracking branch 'frappe/develop' into develop 2015-07-23 22:10:40 +09:00
Tsutomu Mimori
982f4ae44d Removed HTML from messages 2015-07-23 22:09:35 +09:00
Anand Doshi
9257413b68 [minor] Added 'Import Data' in sample data 2015-07-23 18:16:44 +05:30
Neil Trini Lasrado
c723c8b5aa Disable Capacity Planning label changed to Disable Capacity Planning & Time Tracking in Manufacturing Settings 2015-07-23 17:43:27 +05:30
Neil Trini Lasrado
2771b7d828 Track Operations removed and Global Switch added to disable capacity planning in manufacturing settings 2015-07-23 17:39:35 +05:30
Anand Doshi
75ebed815f Merge pull request #3711 from nabinhait/budget
Validation on Account for assigning budget
2015-07-23 17:26:56 +05:30
Nabin Hait
975ef07c48 Merge pull request #3706 from neilLasrado/variant
Fetch Template Bom if no BOM is set against Item Variant in Production Order
2015-07-23 17:26:11 +05:30
Nabin Hait
f666535223 [fix] gross profit report 2015-07-23 17:08:44 +05:30
Nabin Hait
08fb19ac8c Validation on Account for assigning budget 2015-07-23 16:59:43 +05:30
Anand Doshi
db9762be3f Merge pull request #3712 from rmehta/setup-wizard-fix
[fix] contact name in setup wizard
2015-07-23 16:46:09 +05:30
Anand Doshi
03ae61afce Merge pull request #3681 from rmehta/sample-data
[enhancement] update to setup wizard, added users, employees, sample data
2015-07-23 16:45:28 +05:30
Anand Doshi
1847b705fe Merge pull request #3704 from nabinhait/fix2
[fix] SMS status and log
2015-07-23 16:45:00 +05:30
Anand Doshi
4a573a7e8b Merge pull request #3709 from nabinhait/contacts
[cleanup] Party Type deleted
2015-07-23 16:41:36 +05:30
Nabin Hait
f74b9b06f7 Merge pull request #3708 from neilLasrado/material-request
Fetch items from Packing List if Exists in Sales Order while raising …
2015-07-23 15:21:50 +05:30
Nabin Hait
2820a8749f Merge pull request #3710 from neilLasrado/stock-report
Opening Balance row added to Stock Ledger Report
2015-07-23 15:21:26 +05:30
Rushabh Mehta
41b4864f0c Merge pull request #3713 from neilLasrado/manage-variants
Fixes for Item Variants
2015-07-23 15:01:28 +05:30
Neil Trini Lasrado
13df8a40ef Validation added to prevent user to Manage Variants if Item Template is Unsaved. Prevented message stating variants updated while saving item template if there are no variants against that item Template 2015-07-23 12:46:59 +05:30
Rushabh Mehta
7cfa5f0508 [fix] contact name in setup wizard 2015-07-23 12:39:44 +05:30
Nabin Hait
bb274fce2e [cleanup] Party Type deleted 2015-07-23 11:45:30 +05:30
Rushabh Mehta
fec61fe33e [minor] fix report type for Accounts Payable 2015-07-23 10:39:13 +05:30
Neil Trini Lasrado
d0387f41df Opening Balance row added to Stock Ledger Report 2015-07-22 18:44:59 +05:30
Neil Trini Lasrado
05d8174696 Fetch items from Packing List if Exists in Sales Order while raising Material Request against SO 2015-07-22 16:31:34 +05:30
Rushabh Mehta
ba02ce6adc [docs] added description 2015-07-22 15:07:48 +05:30
Anand Doshi
886def0a69 [fix] convert Item and Item Grid images to absolute urls 2015-07-22 14:43:37 +05:30
Anand Doshi
7590aa2524 [minor] raise EmptyStockReconciliationItemsError when no change in any of the items 2015-07-22 14:43:36 +05:30
Neil Trini Lasrado
8b48ceab8c Removed logic for get_item_details in Production Planning Tool, Used get_item_details function of Production Order instead 2015-07-22 12:42:21 +05:30
Nabin Hait
d900e12ae7 Change log for sms 2015-07-22 12:21:55 +05:30
Nabin Hait
098760f0e2 [fix] SMS status and log 2015-07-22 12:17:48 +05:30
Neil Trini Lasrado
cc431716ed Fetch Template Bom if no BOM is set against Item Variant in Production Order 2015-07-22 12:13:47 +05:30
Anand Doshi
f5ea801b69 Merge pull request #3700 from nabinhait/fix1
[report] Letter Head option in General Ledger
2015-07-21 12:19:57 +05:30
Nabin Hait
e2b8ccf1bb [report] Letter Head option in General Ledger report 2015-07-21 12:02:36 +05:30
Anand Doshi
f447c8258a [minor] Newsletter Message should be mandatory 2015-07-20 16:10:04 +05:30
Nabin Hait
f78ffd84b4 Merge branch 'develop' 2015-07-20 15:22:10 +05:30
Nabin Hait
63d345c6ab bumped to version 5.2.1 2015-07-20 15:52:10 +06:00
Anand Doshi
d0d1af2072 Merge pull request #3696 from nabinhait/fix1
[fix][report] Show only active employee in Employee leave balance report
2015-07-20 13:27:47 +05:30
Anand Doshi
83694fd180 [minor] removed is_group from search fields of Account 2015-07-20 13:26:22 +05:30
Anand Doshi
fc353efeca Merge pull request #3670 from neilLasrado/expense-claim
Default Expense Account added to Expense Claim Type.
2015-07-20 13:04:33 +05:30
Anand Doshi
16edf8b478 Merge pull request #3685 from nabinhait/fix6
[fix] Fetch debit/credit from reference journal entry
2015-07-20 13:00:10 +05:30
Nabin Hait
c9e4fbeda0 [fix][report] Show only active employee in Employee leave balance report 2015-07-20 12:57:48 +05:30
Anand Doshi
46ae789f2f Merge pull request #3682 from anandpdoshi/anand-july-17
Remove 'Stopped' banner in Sales Order, show ERPNext icon instead of 'ERPNext'
2015-07-20 12:57:17 +05:30
Anand Doshi
a9a284a5ae Merge pull request #3693 from rmehta/close-task
[minor] close button for task and item not found error fix
2015-07-20 12:56:50 +05:30
Rushabh Mehta
823e88d5bd [minor] close button for task and item not found error fix 2015-07-20 10:56:39 +05:30
Nabin Hait
1be94efcfa [fix] Fetch debit/credit from reference journal entry 2015-07-17 17:25:52 +05:30
Anand Doshi
a5e9c71397 [ui] changed Learn icon 2015-07-17 15:55:10 +05:30
Anand Doshi
285135da8e [ui] Remove 'Stopped' alert banner in Sales Order 2015-07-17 15:14:40 +05:30
Anand Doshi
906c2babaa [ui] Show ERPNext icon instead of ERPNext in navbar 2015-07-17 15:14:39 +05:30
Nabin Hait
14a394cde1 Update fields_to_be_renamed.py 2015-07-17 15:14:19 +05:30
Nabin Hait
3c821c89f2 Update rename_table_fieldnames.py 2015-07-17 15:13:29 +05:30
Nabin Hait
a041297861 Update rename_total_fields.py 2015-07-17 15:12:52 +05:30
Rushabh Mehta
856ee10dc4 [enhancement] update to setup wizard, added users, employees, sample data 2015-07-17 15:03:18 +05:30
Nabin Hait
1401e3f679 Update rename_total_fields.py 2015-07-17 14:43:19 +05:30
Nabin Hait
dae29bf2d4 Update fields_to_be_renamed.py 2015-07-17 14:42:46 +05:30
Nabin Hait
0a3be6da27 Update rename_table_fieldnames.py 2015-07-17 14:39:41 +05:30
Nabin Hait
3631e9cbe0 Merge branch 'develop' 2015-07-16 17:15:41 +05:30
Nabin Hait
1c9a7d2a1b bumped to version 5.2.0 2015-07-16 17:45:40 +06:00
Anand Doshi
972f2f9194 [change-log] 2015-07-16 16:19:30 +05:30
Anand Doshi
239296d16a Merge pull request #3657 from nabinhait/fix4
Reserved warehouse should not be validated on cancellation of sales order
2015-07-16 15:57:59 +05:30
Anand Doshi
3210db9056 Merge pull request #3656 from rmehta/sms-log
[fix] create SMS Log
2015-07-16 15:56:08 +05:30
Neil Trini Lasrado
feda4f9bc9 Default Expense Account added to Expense Claim Type. Fetch account while making Bank Entry 2015-07-16 15:44:56 +05:30
Anand Doshi
f6954fb798 Merge pull request #3663 from neilLasrado/bom
Bom
2015-07-16 15:02:40 +05:30
Anand Doshi
c6656e68b8 Merge pull request #3666 from nabinhait/patch-fix
[patch][fix] Sales BOM should be renamed before rename_table_fields patch
2015-07-16 14:55:35 +05:30
Anand Doshi
a39387d352 Merge pull request #3664 from rmehta/develop
[cleanup] removed welcome emails
2015-07-16 14:25:24 +05:30
Rushabh Mehta
f3791797d6 [fix] [patch] 2015-07-16 14:17:59 +05:30
Rushabh Mehta
ea4d63cef3 [cleanup] removed welcome emails 2015-07-16 14:17:59 +05:30
Nabin Hait
5464ca8a73 [patch][fix] Sales BOM should be renamed before rename_table_fields patch 2015-07-16 12:19:57 +05:30
Rushabh Mehta
6c6875f503 [cleanup] removed welcome emails 2015-07-16 11:53:18 +05:30
Neil Trini Lasrado
20523c45c7 Patch for default BOM 2015-07-16 11:27:06 +05:30
Neil Trini Lasrado
0248811e53 Fixed deafault BOM problem 2015-07-16 11:26:40 +05:30
Rushabh Mehta
93416ee72c Update sponsors.md 2015-07-15 16:42:46 +05:30
Rushabh Mehta
51e7086a08 [patch] rename roles 2015-07-15 16:30:49 +05:30
Anand Doshi
5e849ae53e [help] added new links to Learn 2015-07-15 15:23:02 +05:30
Rushabh Mehta
de0db0d000 Merge pull request #3658 from anandpdoshi/anand-july-15
[fix] Mozilla hack for images in table for print
2015-07-15 12:58:19 +05:30
Anand Doshi
f3a67c4533 [fix] Mozilla hack for images in table for print 2015-07-15 12:37:45 +05:30
Nabin Hait
0847f9a074 Reserved warehouse should not be validated on cancellation of sales order 2015-07-14 18:23:05 +05:30
Anand Doshi
9490c21b8a Merge pull request #3641 from rmehta/role-rename
[rename] Material User > Stock User
2015-07-14 12:10:48 +05:30
Rushabh Mehta
bdb71bca4e [perm] added stock, project user for company 2015-07-14 11:54:42 +05:30
Anand Doshi
e8861e2871 Merge pull request #3649 from rmehta/purchase-invoice-fix
[fix] supplier invoice number fix
2015-07-14 11:50:07 +05:30
Anand Doshi
b084b5e449 Merge pull request #3651 from rmehta/pos-default-pay-fix
[fix] pos default payment #3631
2015-07-14 11:49:46 +05:30
Anand Doshi
41d3e57702 Merge pull request #3650 from rmehta/time-log-fix-2
[fix] overlap fix in time log #3647
2015-07-14 11:45:49 +05:30
Anand Doshi
9df2899f72 Merge pull request #3648 from rmehta/time-log-fix
[fixes] hours in time-log #3644, project buttons on condition, removed Guest permission in notification_control
2015-07-14 11:25:46 +05:30
Rushabh Mehta
dacf127f1b [fix] time log overlap condition, #SavedByATestCase 2015-07-14 11:06:28 +05:30
Rushabh Mehta
2b49f9b30a [fix] pos default payment #3631 2015-07-14 11:01:42 +05:30
Rushabh Mehta
533434e878 [fix] overlap fix in time log #3647 2015-07-14 10:39:33 +05:30
Rushabh Mehta
1956028ddc [fix] supplier invoice number fix 2015-07-14 10:26:50 +05:30
Rushabh Mehta
a87dc3b4e6 [minor] move position in accounts settings 2015-07-14 10:22:07 +05:30
Rushabh Mehta
97b3f750c9 [fixes] hours in time-log #3644, project buttons on condition, removed Guest permission in notification_control 2015-07-14 10:14:48 +05:30
Anand Doshi
c41b63eff1 Merge pull request #3642 from anandpdoshi/anand-july-13
Fixes to Cart
2015-07-13 16:56:37 +05:30
Anand Doshi
e6f7ac961f [fix] Add to Cart visibility, Customer's Price List in Shopping Cart and Address creation from Shopping Cart 2015-07-13 16:24:37 +05:30
Rushabh Mehta
cf26964deb Merge pull request #3640 from anandpdoshi/anand-july-13
Fixes to Issues
2015-07-13 15:37:11 +05:30
Rushabh Mehta
94157334a7 [rename] Material User > Stock User 2015-07-13 15:06:12 +05:30
Anand Doshi
c530161de0 [fix] Item image urls can now have paranthesis 2015-07-13 15:05:39 +05:30
Nabin Hait
2212ae12d8 Merge branch 'develop' 2015-07-13 14:26:23 +05:30
Nabin Hait
54ade0d26c bumped to version 5.1.6 2015-07-13 14:56:23 +06:00
Nabin Hait
f043760526 Merge pull request #3639 from neilLasrado/develop
Sales BOM to Product Bundle rename changes
2015-07-13 14:22:10 +05:30
Neil Trini Lasrado
1cd049d824 Sales BOM to Product Bundle rename changes 2015-07-13 14:17:42 +05:30
Nabin Hait
0a45260ed9 Merge branch 'develop' 2015-07-13 13:09:05 +05:30
Nabin Hait
1540ad12f9 bumped to version 5.1.5 2015-07-13 13:39:05 +06:00
Nabin Hait
76bd015b2c Merge pull request #3637 from rmehta/time-log-filter
[minor] [enhancement] added employee filter in timelog #3607
2015-07-13 13:04:03 +05:30
Rushabh Mehta
5054a3955b Update CONTRIBUTING.md 2015-07-13 12:54:08 +05:30
Nabin Hait
1a0713e4b9 Merge pull request #3584 from neilLasrado/develop
Minor fixes
2015-07-13 12:49:46 +05:30
Rushabh Mehta
e9604d8484 [minor] [enhancement] added employee filter in timelog #3607 2015-07-13 12:47:45 +05:30
Neil Trini Lasrado
008d1a0334 Fixes in Stock Entry 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
fe2ffaeafa Fixes in Production Planning Tool 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
dcef448f1e Planned Start Date added to Production Planning Tool 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
6224cfc414 Manage Variants added in Tools under Stock Module 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
700434ff37 has_variants made 'no copy' in Item Master 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
4089b3d376 Salary Slip renamed to Process Payroll 2015-07-13 12:41:28 +05:30
Neil Trini Lasrado
6cfab43d5f Renamed Depends on LWP field in the Earning and Deduction table of Salary Slip. 2015-07-13 12:41:27 +05:30
Neil Trini Lasrado
09a66c4201 Fixed issue with Customer Contacts in Transaction Documents 2015-07-13 12:41:27 +05:30
Neil Trini Lasrado
ed8cecbdd8 Sales BOM renamed to Product Bundle 2015-07-13 12:41:27 +05:30
Neil Trini Lasrado
c70109d0c5 Item table made mandatory in Stock Reconciliation 2015-07-13 12:40:57 +05:30
Neil Trini Lasrado
ccf8c337f7 Expected Delivery date validation changed to message 2015-07-13 12:40:57 +05:30
Nabin Hait
6809b4d86c Merge pull request #3636 from neilLasrado/po
Patch for Production Order Track Operation
2015-07-13 12:38:45 +05:30
Neil Trini Lasrado
cc08c68153 Patch for Production Order Track Operation 2015-07-13 12:35:20 +05:30
Nabin Hait
7daa7900ea Merge pull request #3614 from neilLasrado/po
Track Operations added to Production Order
2015-07-13 12:29:45 +05:30
Nabin Hait
7641f3fe53 Merge pull request #3635 from nabinhait/fix3
Reserved warehouse should not be validated on cancellation of sales order
2015-07-13 12:28:49 +05:30
Nabin Hait
fe2f51bbbc Merge pull request #3628 from nabinhait/sponsors
Change log and Sponsors page
2015-07-13 12:27:30 +05:30
Neil Trini Lasrado
4f33249e1c Fixes in Production Order 2015-07-13 12:26:33 +05:30
Nabin Hait
b95b606f25 sponsors page and change log 2015-07-13 12:26:24 +05:30
Nabin Hait
e690f245f2 Change log and Sponsors page 2015-07-13 12:26:24 +05:30
Neil Trini Lasrado
5da4d857c9 Track Operations added to Production Order 2015-07-13 12:01:57 +05:30
Nabin Hait
6e38e917eb Reserved warehouse should not be validated on cancellation of sales order 2015-07-13 11:36:36 +05:30
Rushabh Mehta
f3b0b95b15 [fix] [filter] for general ledger 2015-07-13 10:24:25 +05:30
Nabin Hait
7b0f1ffb2d Merge pull request #3627 from nabinhait/fix2
PP Tool: Create production order if applicable for item
2015-07-10 17:32:16 +05:30
Nabin Hait
97bb6bbaf4 Merge pull request #3621 from neilLasrado/batch
Validation added to prevent adding items with expired batch numbers t…
2015-07-10 17:31:52 +05:30
Neil Trini Lasrado
cb4b2ec52a Fixes in validate baatch function 2015-07-10 17:31:06 +05:30
Nabin Hait
f18bbcef86 PP Tool: Create production order if applicable for item 2015-07-10 17:31:03 +05:30
Nabin Hait
27976382d8 Merge pull request #3626 from nabinhait/credit_days
minor fix in due date validation
2015-07-10 17:13:15 +05:30
Nabin Hait
93d3c82737 minor fix in due date validation 2015-07-10 17:12:08 +05:30
Neil Trini Lasrado
03bf529622 Validation added to prevent adding items with expired batch numbers to stock ledger entry 2015-07-10 16:20:21 +05:30
Nabin Hait
6c4085fc0c Merge pull request #3616 from nabinhait/credit_days
Customer's credit days based on fixed days / last day of the next month
2015-07-10 16:16:14 +05:30
Nabin Hait
c37484c8da Merge pull request #3622 from rmehta/minor-fixes
[fix] cart and general leger report
2015-07-10 16:12:01 +05:30
Rushabh Mehta
b4ec294463 Merge pull request #3625 from neilLasrado/task
Validation added to prevent task being closed with open dependent tasks
2015-07-10 14:30:46 +05:30
Neil Trini Lasrado
58406a920c Validation added to prevent task being closed with open dependent tasks 2015-07-10 12:57:49 +05:30
Rushabh Mehta
98311f4394 Merge pull request #3624 from pdvyas/lang
Fix lang code for česky and update translations
2015-07-10 12:37:31 +05:30
Pratik Vyas
53829707ad Fix lang code for česky 2015-07-10 12:05:53 +05:30
Pratik Vyas
fcc31028c6 Update translations 2015-07-10 12:05:24 +05:30
Rushabh Mehta
fc3d87181a [fix] cart and general leger report 2015-07-10 10:11:07 +05:30
Nabin Hait
6336ff7323 minor fixes 2015-07-09 19:48:21 +05:30
Nabin Hait
fde13e666a Merge pull request #3609 from rmehta/address-link
[fix] link address via owner, if created in portal #3540
2015-07-09 19:09:39 +05:30
Nabin Hait
f80c09290e Merge pull request #3610 from nabinhait/variants
Adding rows not allowed in Variant table in Manage Variants and Item
2015-07-09 19:07:56 +05:30
Nabin Hait
b797963bd8 Merge pull request #3618 from neilLasrado/naming
Validation added in Production Order
2015-07-09 18:53:39 +05:30
Nabin Hait
03b42a7934 Merge pull request #3619 from neilLasrado/contact
Allowed same contact to be Linked to Customer AND Supplier AND Sales …
2015-07-09 18:52:22 +05:30
Nabin Hait
7e9ff99a6c Merge pull request #3620 from nabinhait/currency_symbol
Currency symbol fixed in sales invoice outstanding and advance amount
2015-07-09 18:51:38 +05:30
Nabin Hait
5cbe3441e8 Reload doctype in patch 2015-07-09 18:42:15 +05:30
Nabin Hait
0724449d0e [patch] Set 'Credit days based on' in existing customer, customer group and company 2015-07-09 17:49:50 +05:30
Neil Trini Lasrado
5a6ff218e8 Allowed same contact to be Linked to Customer AND Supplier AND Sales Partner 2015-07-09 17:49:40 +05:30
Nabin Hait
122e4e0a96 Currency symbol fixed in sales invoice outstanding and advance amount 2015-07-09 17:36:58 +05:30
Neil Trini Lasrado
e233f0e2ff Validation added in Production Order to prevent PO against Item Template or if Allow PO is No in Item Master 2015-07-09 17:35:51 +05:30
Nabin Hait
40e92b679b Posting date trigger function commonified 2015-07-09 17:12:23 +05:30
Nabin Hait
4770a1abb5 Customer's credit days based on fixed days / last day of the next month 2015-07-09 16:35:53 +05:30
Rushabh Mehta
ccb9117ba5 [minor] Added employees in Newsletter List 2015-07-09 13:56:02 +05:30
Nabin Hait
db938762c7 [fix] Adding rows not allowed in Variant table in Manage Variants and Item form 2015-07-09 11:55:38 +05:30
Nabin Hait
0910fc3b25 Merge pull request #3605 from nabinhait/testcases
Test case fixed
2015-07-09 11:28:36 +05:30
Rushabh Mehta
f0737667c6 [fix] link address via owner, if created in portal #3540 2015-07-09 11:09:01 +05:30
Nabin Hait
2d83122c6b removed client side test cases 2015-07-08 18:02:42 +05:30
Nabin Hait
e2b7f832cc Test case fixed 2015-07-08 17:56:06 +05:30
Nabin Hait
6a6958db5c Merge branch 'develop' 2015-07-08 16:53:55 +05:30
Nabin Hait
ab1acb460b bumped to version 5.1.4 2015-07-08 17:23:55 +06:00
Nabin Hait
48d71fa7f7 Merge pull request #3602 from nabinhait/develop
Change log
2015-07-08 16:47:14 +05:30
Nabin Hait
30960e6a06 Change log added 2015-07-08 16:46:28 +05:30
Nabin Hait
736000c223 Merge pull request #3600 from neilLasrado/batch
Fixed issues in Expired Batches while making Stock Entry
2015-07-08 16:10:21 +05:30
Nabin Hait
4017bfcd2e Merge pull request #3591 from rmehta/salary-manager-fix
[fixes] salary manager #3554
2015-07-08 15:39:33 +05:30
Nabin Hait
e594e5de49 Merge pull request #3596 from neilLasrado/pos
Mode of Payment added to POS Profile
2015-07-08 15:36:30 +05:30
Nabin Hait
1f1f14be39 Merge pull request #3599 from nabinhait/develop
Multiple fixes
2015-07-08 15:33:57 +05:30
Neil Trini Lasrado
ebb60f5dbc Fixed issues in Expired Batches while making Stock Entry 2015-07-08 15:24:02 +05:30
Neil Trini Lasrado
75b00e3958 Mode of Payment added to POS Profile 2015-07-08 14:43:47 +05:30
Nabin Hait
5e3646ad6e validation message fix 2015-07-08 14:39:03 +05:30
Nabin Hait
4439d8264f minor fix 2015-07-08 14:32:56 +05:30
Nabin Hait
00d79eb68d minor fix 2015-07-08 14:32:27 +05:30
Nabin Hait
28a9e35de9 Validate item rate with reference document with tolerance 0.009 2015-07-08 13:10:59 +05:30
Nabin Hait
c450536a2c [fix] Map values in Debit / Credit Note from Stock Entry 2015-07-08 13:10:59 +05:30
Nabin Hait
3b3c48c877 [fix] Set Customer name in opportunity as per company name in lead 2015-07-08 13:10:59 +05:30
Rushabh Mehta
621d6eac3c [minor] added calendar hooks 2015-07-08 12:39:27 +05:30
Rushabh Mehta
f9b356992a [fixes] salary manager #3554 2015-07-07 16:30:29 +05:30
Nabin Hait
c516e1871d Merge branch 'develop' 2015-07-06 15:32:32 +05:30
Nabin Hait
9a38e669ef bumped to version 5.1.3 2015-07-06 16:02:32 +06:00
Nabin Hait
143f2c6faf Merge pull request #3585 from nabinhait/change_log
Added change log
2015-07-06 15:15:29 +05:30
Nabin Hait
9269813207 Added change log 2015-07-06 15:13:35 +05:30
Nabin Hait
0e6f92efa8 Merge pull request #3571 from neilLasrado/item-varients
Fixes for Item Attributes
2015-07-06 14:56:33 +05:30
Neil Trini Lasrado
1a0e86f11d Update item_attribute.py
Error Description Changed
2015-07-06 14:46:06 +05:30
Nabin Hait
73b7efd61d Merge pull request #3583 from rmehta/quotation-list-fix
[fix] quotation list #3492
2015-07-06 14:31:23 +05:30
Nabin Hait
4c4a5b968c Merge pull request #3576 from nabinhait/variant
[fix][patch] delete item variant attributes if no variants exists against that item
2015-07-06 14:30:48 +05:30
Nabin Hait
7b5ac6396a Merge pull request #3575 from nabinhait/batch_report
[fix] Hide zero balance rows in batch-wise balance history report
2015-07-06 14:30:23 +05:30
Nabin Hait
01771e8afc Merge pull request #3573 from rmehta/fix-labels
[fix] [minor] fix customer_name, supplier_name labels
2015-07-06 14:30:13 +05:30
Nabin Hait
347c4affe9 Merge pull request #3567 from rmehta/item-description-mozilla-fix
[fix] item image in mozilla #3412 #3413
2015-07-06 14:27:34 +05:30
Nabin Hait
526957505f Merge pull request #3569 from rmehta/employee-unset-user-id
[fix] remove user permission if user id is unset #3447
2015-07-06 14:27:22 +05:30
Nabin Hait
faa3416852 Merge pull request #3570 from rmehta/remove-masters-from-setup
[minor] remove the term 'Masters' from setup, it is confusing and not used anywhere, add Company to Accounts tab
2015-07-06 14:26:51 +05:30
Rushabh Mehta
56912791e2 [fix] quotation list #3492 2015-07-06 11:14:31 +05:30
Rushabh Mehta
38647c68b9 Merge pull request #3579 from neilLasrado/autocomplete
Autocomplete issues fixed in Manage Variants
2015-07-05 13:52:56 +05:30
Neil Trini Lasrado
4d64acfafc Autocomplete issues fixed in Manage Variants 2015-07-04 14:50:00 +05:30
Nabin Hait
d7441ec051 [fix][patch] delete item variant attributes if no variants exists against that item 2015-07-03 19:20:27 +05:30
Rushabh Mehta
0f15273bd7 Merge pull request #3572 from tmimori/develop
Fix for Monthly Attendance Report #3402
2015-07-03 15:49:26 +05:30
Nabin Hait
24efb3122a [fix] Hide zero balance rows in batch-wise balance history report 2015-07-03 15:20:14 +05:30
Rushabh Mehta
85e6f5d04e [fix] [minor] fix customer_name, supplier_name labels 2015-07-03 12:59:08 +05:30
Neil Trini Lasrado
1faaf71dfc Auto-Capitalize Item Attribute Abbreation, Prevent attribute to be deleated if Variant exists 2015-07-03 12:44:01 +05:30
Tsutomu Mimori
5a0fbff1a3 #3402 2015-07-03 16:08:02 +09:00
Rushabh Mehta
7278c0ae85 [minor] remove the term 'Masters' from setup, it is confusing and not used anywhere, add Company to Accounts tab 2015-07-03 12:21:50 +05:30
Rushabh Mehta
5688a6c31a [fix] remove user permission if user id is unset #3447 2015-07-03 11:34:53 +05:30
Rushabh Mehta
71349d221b [fix] item image in mozilla #3412 #3413 2015-07-03 10:43:35 +05:30
Nabin Hait
b7219dc698 Merge branch 'develop' 2015-07-02 17:58:40 +05:30
Nabin Hait
37c6ce7b1e bumped to version 5.1.2 2015-07-02 18:28:40 +06:00
Nabin Hait
7028ba507e Merge pull request #3561 from nabinhait/develop
Fixes
2015-07-02 17:55:18 +05:30
Nabin Hait
fcee17fd16 Removed purchase item validation 2015-07-02 17:51:35 +05:30
Nabin Hait
5906f02e3a update item image in invoice if item exists 2015-07-02 17:51:35 +05:30
Nabin Hait
721dcb1870 Merge branch 'develop' 2015-07-02 16:33:52 +05:30
Nabin Hait
6385967ccd bumped to version 5.1.1 2015-07-02 17:03:52 +06:00
Nabin Hait
81a977cacf Merge pull request #3559 from nabinhait/develop
Fixes
2015-07-02 16:32:34 +05:30
Nabin Hait
34058ded0e [fix] Update item image in sales invoice 2015-07-02 16:31:55 +05:30
Nabin Hait
e98120b716 [fix] Change log path 2015-07-02 16:29:28 +05:30
Nabin Hait
50e363b24e Merge branch 'develop' 2015-07-02 15:28:49 +05:30
Nabin Hait
bc176b6bf8 bumped to version 5.1.0 2015-07-02 15:58:49 +06:00
Nabin Hait
784b49e54e change log 2015-07-02 15:28:15 +05:30
Nabin Hait
04fb6e1a45 Merge pull request #3558 from nabinhait/develop
Change log
2015-07-02 15:22:20 +05:30
Nabin Hait
dffd7c3889 Change log 2015-07-02 15:21:25 +05:30
Nabin Hait
0c7594e5ed Merge pull request #3557 from rmehta/item-description-in-form
[fix] show item description in form grid based on in_list_view
2015-07-02 15:19:24 +05:30
Rushabh Mehta
5105f909d6 [fix] show item description in form grid based on in_list_view 2015-07-02 15:09:18 +05:30
Nabin Hait
2ab9d6e92c Merge pull request #3552 from nabinhait/develop
Recurring docs should not consider Stopped documents and should be scheduled for hourly
2015-07-02 14:42:57 +05:30
Nabin Hait
7580723ab3 Recurring docs should not consider Stopped documents and should be scheduled for hourly 2015-07-02 14:41:27 +05:30
Nabin Hait
52fef71c14 Merge pull request #3543 from rmehta/against-account-fix
Fix against account to show party instead of account
2015-07-02 14:28:11 +05:30
Rushabh Mehta
2cd02af80a [fix] patch date 2015-07-02 14:25:51 +05:30
Rushabh Mehta
0b0ec3536c [change-log] added 2015-07-02 14:25:51 +05:30
Rushabh Mehta
6b35ea873b [fix] against account in general ledger will show party 2015-07-02 14:25:51 +05:30
Nabin Hait
ecf220a721 Merge pull request #3549 from neilLasrado/item-varients
Validation changed for Item Template cannot have Stock
2015-07-02 14:18:31 +05:30
Nabin Hait
04fb1c7fe4 Merge pull request #3550 from neilLasrado/item-desc
Image feild added to Sales Invoice & Purchase Invoice
2015-07-02 14:17:52 +05:30
Neil Trini Lasrado
53bd62eafc Validation changed for Item Template cannot have Stock 2015-07-02 14:15:23 +05:30
Nabin Hait
ff68bf2609 Merge pull request #3551 from nabinhait/develop
Fixes
2015-07-02 14:10:58 +05:30
Nabin Hait
fdd0db3459 Update project completion percentage and costing after syncing task 2015-07-02 14:09:49 +05:30
Nabin Hait
f92465981c datetime issue fixed in maintenance schedule 2015-07-02 14:09:49 +05:30
Nabin Hait
885c70984d [fix] Always show Sales invoice in Gross profit report 2015-07-02 14:09:49 +05:30
Neil Trini Lasrado
9c15ef903d Image feild added to Sales Invoice & Purchase Invoice 2015-07-02 13:09:57 +05:30
Rushabh Mehta
bc799885d0 [fix] bom client script 2015-07-02 12:44:16 +05:30
Nabin Hait
cb129264cb Merge pull request #3386 from neilLasrado/item-varients
[redesign] Manage Item varients
2015-07-01 18:29:04 +05:30
Neil Trini Lasrado
fe9cd1d875 More Fixes in Manage Varients 2015-07-01 14:41:30 +05:30
Neil Trini Lasrado
64fbe955c7 Modified Date changed for Item Doctype 2015-07-01 14:04:00 +05:30
Neil Trini Lasrado
0988440fd9 Fixes for Manage Variants 2015-07-01 13:17:15 +05:30
Neil Trini Lasrado
274dd4ada0 Fixed Manage Variants Attribute autocomplete appearance. 2015-07-01 12:51:40 +05:30
Neil Trini Lasrado
724fd82419 Fixes in Manage Variants 2015-07-01 12:51:40 +05:30
Neil Trini Lasrado
3f2604eff6 Patch for Item Variants 2015-07-01 12:51:40 +05:30
Neil Trini Lasrado
c761fefb78 more fixes in test records 2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
203cb10ef7 fixes in test cases 2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
90c66b1998 test cases added 2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
fed431f908 Code Fixes in Manage Variants 2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
bd9745ba72 Rename Item Variant from Manage Variants feature Added. 2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
8fb123b20e item variants, creation, deleation and update logic added.
logic added to copy changes in template to variants
2015-07-01 12:51:11 +05:30
Neil Trini Lasrado
333ccd212b variants combination generation logic added 2015-07-01 12:51:10 +05:30
Neil Trini Lasrado
c8cc8b7115 manage variants new doctype created 2015-07-01 12:51:10 +05:30
Nabin Hait
ec44fa95ce Merge pull request #3537 from neilLasrado/project
Fixed Issues in Project Task
2015-06-30 17:29:19 +05:30
Neil Trini Lasrado
a25e8ea0bc Fixed Issues in Project Task 2015-06-30 17:15:13 +05:30
Rushabh Mehta
ea02b9a5c3 Merge pull request #3530 from anandpdoshi/anand-june-29
[fix] Item Variant Attribute autocomplete appearance. Fixes #3488, #3515, #3525
2015-06-30 13:05:19 +05:30
Rushabh Mehta
74a63bf003 Merge pull request #3531 from pdvyas/exchange-rate-api
Change currency exchange rate api to fixer.io
2015-06-30 12:46:52 +05:30
Pratik Vyas
a0f2510b01 Change currency exchange rate api to fixer.io 2015-06-30 12:36:17 +05:30
Anand Doshi
0820161157 [fix] Item Variant Attribute autocomplete appearance. Fixes #3488, #3515, #3525 2015-06-29 20:57:06 -07:00
Nabin Hait
56bc215855 Merge pull request #3505 from neilLasrado/print-format
Recurring Invoice Print Format
2015-06-29 18:54:24 +05:30
Nabin Hait
8687d25f7e Merge pull request #3526 from neilLasrado/minor-fixes
Minor fixes
2015-06-29 18:53:10 +05:30
Nabin Hait
9cea01fa8b Merge pull request #3527 from nabinhait/develop
Journal Entry list view and delete events via query
2015-06-29 18:39:43 +05:30
Nabin Hait
e06d01e3ed Delete events via query instead of delete_doc function, to save time 2015-06-29 18:38:38 +05:30
Nabin Hait
11243a4fb4 Show amount in Journal Entry list view 2015-06-29 18:38:38 +05:30
Neil Trini Lasrado
b9e5cd0df4 Fixed lead status not updating on Creation of oppurtunity issue 2015-06-29 17:01:32 +05:30
Neil Trini Lasrado
a1f1edc786 Typo fixes in Sales Person 2015-06-29 16:04:12 +05:30
Neil Trini Lasrado
e2d8dd0663 added recurring print format to sales/purchase invoice and order 2015-06-29 12:50:41 +05:30
Nabin Hait
d1605c5cb2 Merge branch 'develop' 2015-06-27 13:09:05 +05:30
Nabin Hait
64ca52fb77 bumped to version 5.0.29 2015-06-27 13:39:05 +06:00
Nabin Hait
2f11a3bdaf Merge pull request #3523 from nabinhait/develop
Multiple fixes
2015-06-27 13:07:44 +05:30
Nabin Hait
943dc1f59c Merge branch 'develop' 2015-06-27 13:07:01 +05:30
Nabin Hait
6d1c994bc9 bumped to version 5.0.28 2015-06-27 13:37:01 +06:00
Nabin Hait
93cdee4503 [fix] Escape values in queries 2015-06-27 12:51:00 +05:30
Nabin Hait
dfac6848cc In list view property added in BOM 2015-06-26 14:42:51 +05:30
Nabin Hait
8ad0b4e0b9 Show Issue id in list view from customer login 2015-06-26 14:42:51 +05:30
Nabin Hait
b8cd92f1aa Merge pull request #3517 from neilLasrado/batch
Added validation to prevent transfer of raw material from an expired …
2015-06-25 18:20:46 +05:30
Nabin Hait
1fe48cb820 Merge pull request #3514 from anandpdoshi/anand-june-24
[fix] Use per_billed instead of per_delivered and per_received for open notification
2015-06-25 18:04:26 +05:30
Anand Doshi
723b046c5b [fix] Use per_billed instead of per_delivered and per_received for open notification 2015-06-24 19:21:52 -04:00
Neil Trini Lasrado
035160c9a6 Added validation to prevent transfer of raw material from an expired batch for manufacturing 2015-06-24 15:25:57 +05:30
Nabin Hait
01c7ce1da3 Merge pull request #3508 from nabinhait/develop
[fix] validate items in stock entry for subcontracting against PO
2015-06-23 11:12:23 +05:30
Nabin Hait
9cf2910ba1 [fix] validate items in stock entry for subcontracting against purchase order 2015-06-23 11:07:34 +05:30
Nabin Hait
c8da7b7d32 Merge branch 'develop' 2015-06-23 10:27:59 +05:30
Nabin Hait
9679d31397 bumped to version 5.0.27 2015-06-23 10:57:59 +06:00
Nabin Hait
38bebe1b83 Merge pull request #3503 from neilLasrado/leave-application
Fixed bugs in Calender View for Leave Application
2015-06-22 19:32:16 +05:30
Nabin Hait
ffbc11e8de Merge pull request #3504 from nabinhait/develop
Multiple fixes
2015-06-22 19:29:32 +05:30
Nabin Hait
818d9674d9 [fix] Update outstanding amount function fixed if party not mentioned 2015-06-22 18:21:38 +05:30
Neil Trini Lasrado
086f8942eb Fixed bugs in Calender View for Leave Application 2015-06-22 13:51:56 +05:30
Nabin Hait
c3b492b237 [fix] Auto remarks in Journal Entry based on company currency 2015-06-22 07:52:38 +05:30
Nabin Hait
9d0dd5066a Removed 'Root Type' validation for receivable/payable account in sales/purchase invoice 2015-06-22 07:32:46 +05:30
Nabin Hait
e7f479b26a Validate accounting entry agaist Stock account if perpetual inventory enabled 2015-06-22 07:31:49 +05:30
Nabin Hait
7ee45b4af2 [fix] Batch-wise balance history: show records only with batch-id 2015-06-18 15:29:14 +05:30
Nabin Hait
5cce1e0929 Merge pull request #3489 from nabinhait/develop
Opening balance
2015-06-18 10:34:31 +05:30
Nabin Hait
be496bc91c [fix] Trial Balance opening 2015-06-18 10:33:20 +05:30
Nabin Hait
59f063e5c3 [fix] opening balance in general ledger report 2015-06-18 10:33:20 +05:30
Nabin Hait
af5820874c Merge branch 'develop' 2015-06-17 15:51:00 +05:30
Nabin Hait
495db99719 bumped to version 5.0.26 2015-06-17 16:21:00 +06:00
Nabin Hait
123beb5a07 Merge pull request #3484 from rmehta/bom-search-report
[report] BOM Search
2015-06-17 15:38:39 +05:30
Nabin Hait
7ed4e080a2 Merge pull request #3486 from nabinhait/develop
Opening balance
2015-06-17 15:36:06 +05:30
Nabin Hait
e91025c0aa [fix] Opening balance in trial balance and general ledger based on is_opening 2015-06-17 15:35:06 +05:30
Nabin Hait
1ac9f2f50d [fix] Opening balance in trial balance and general ledger based on is_opening 2015-06-17 15:09:40 +05:30
Nabin Hait
bd9aa13db3 Minor issue in naming series 2015-06-17 15:09:40 +05:30
Rushabh Mehta
ed9d5cfdaf [minor] cleanup 2015-06-17 02:13:03 +05:30
Rushabh Mehta
bf4547ca5f [fix] dynamic link in BOM Search report 2015-06-17 02:12:06 +05:30
Rushabh Mehta
b45a6bcb88 [report] BOM Search 2015-06-17 01:54:56 +05:30
Anand Doshi
ac59c2b300 [minor] clear Item's introduction section on refresh 2015-06-16 13:06:48 -04:00
Nabin Hait
6a8d7a1b91 Merge branch 'develop' 2015-06-16 16:50:49 +05:30
Nabin Hait
5d71a28e97 bumped to version 5.0.25 2015-06-16 17:20:49 +06:00
Nabin Hait
7d100a1ee7 Merge pull request #3480 from nabinhait/develop
Indexes
2015-06-16 16:49:26 +05:30
Nabin Hait
81dca110eb Change log added 2015-06-16 16:48:47 +05:30
Nabin Hait
9c852108d0 Added index in sales/purchase invoice and fix in index patch 2015-06-16 16:48:47 +05:30
Nabin Hait
e3ac032696 Merge pull request #3472 from neilLasrado/po
Multiple Fixes
2015-06-16 15:52:48 +05:30
Neil Trini Lasrado
64cacfb077 Fixes in Activity Cost 2015-06-16 15:42:40 +05:30
Neil Trini Lasrado
ae4cc078ea Activity Cost - Mandatory removed for Employee. 2015-06-16 15:30:08 +05:30
Nabin Hait
0ee543e932 Merge pull request #3479 from nabinhait/develop
[fix][report] Payment period based on invoice date
2015-06-16 15:29:14 +05:30
Nabin Hait
a123638d37 [fix][report] Payment period based on invoice date 2015-06-16 15:21:00 +05:30
Nabin Hait
58996985ed Merge pull request #3476 from nabinhait/develop
Expense Approver Query and discount label
2015-06-16 15:01:08 +05:30
Nabin Hait
5d0ce7939f Show only users with Expense Approver role in Expense Claim Approver field 2015-06-15 17:59:37 +05:30
Neil Trini Lasrado
4abf552d7b Over Production Allowance Percentage Setting added to Manufacturing Settings 2015-06-15 15:58:45 +05:30
Nabin Hait
7c5ba957ac Label changed for discount amount in base currency 2015-06-15 15:47:07 +05:30
Nabin Hait
77f04e293a Merge branch 'develop' 2015-06-15 10:35:39 +05:30
Nabin Hait
d1d3237784 bumped to version 5.0.24 2015-06-15 11:05:39 +06:00
Nabin Hait
76f0d26f1e Merge pull request #3471 from nabinhait/develop
Hotfix
2015-06-15 10:32:23 +05:30
Nabin Hait
65922d3079 [fix] supplier invoice date can not be after posting date 2015-06-15 10:23:53 +05:30
Nabin Hait
810041cbe3 [fix] Fixed error due to performance upgrade cleanup 2015-06-15 10:20:11 +05:30
Nabin Hait
b9626659ea Merge pull request #3465 from neilLasrado/po
Po
2015-06-15 10:04:36 +05:30
Nabin Hait
e3d13bee36 Merge pull request #3467 from anandpdoshi/anand-june-12
Fixes
2015-06-15 10:03:20 +05:30
Nabin Hait
13bd538aca Merge branch 'develop' 2015-06-14 22:04:51 +05:30
Nabin Hait
d72a24965b bumped to version 5.0.23 2015-06-14 22:34:51 +06:00
Nabin Hait
dc633fe360 Merge pull request #3470 from nabinhait/develop
Performance upgrade in reports and indexing
2015-06-14 22:01:30 +05:30
Nabin Hait
39046d663d [patch] Add index on Account and GL Entry table 2015-06-14 20:59:28 +05:30
Nabin Hait
6b01abe9ad [report][performance] Speed increased by approx 10 times in Trial Balance, General Ledger, AR/AP, Balance Sheet and P&L Statement 2015-06-14 20:59:28 +05:30
Anand Doshi
63e4d31aa6 [fix] Task should be mandatory in Time Log only when Project is mentioned but Production Order is not 2015-06-12 18:59:18 -04:00
Anand Doshi
f2a0161709 [fix] Don't create Time Logs against Production Order if Workstation is not specified in Operations 2015-06-12 18:58:36 -04:00
Neil Trini Lasrado
3c1a4a0b9b percent_complete made no-copy in Project 2015-06-12 18:34:08 +05:30
Neil Trini Lasrado
82cc2921d1 Validation added to prevent user from creating salary structure with 'From Date' before employee 'Date of joining' 2015-06-12 18:34:08 +05:30
Nabin Hait
87edd86854 Merge branch 'develop' 2015-06-12 18:06:21 +05:30
Nabin Hait
e37dd77923 bumped to version 5.0.22 2015-06-12 18:36:21 +06:00
Nabin Hait
e4f689184f Merge pull request #3459 from neilLasrado/po
Multiple Fixes.
2015-06-12 17:55:23 +05:30
Nabin Hait
85f825e98c Merge pull request #3463 from nabinhait/develop
multiple issues
2015-06-12 17:48:54 +05:30
Nabin Hait
89592c5180 Load tasks in project for printing purpose 2015-06-12 17:37:28 +05:30
Neil Trini Lasrado
587bd144d5 Added Customers Not Buying Since Long Time against Sales Invoice 2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
1f048b2426 Fixes in Activity Cost 2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
1792ff3be7 Validation added in Purchase Invoice to check if Supplier Invoice Date is greater than Posting Date
Check Supplier Invoice Number Uniqueness setting added to Accounts Settings
Validation added in Purchase Invoice to check Supplier Invoice Number Uniqueness if Check Supplier Invoice Number Uniqueness is enabled in Accounts Settings
2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
fc595064e0 validation added to prevent Delivery Date in Porduction Order to be lesser than Planned Start Date 2015-06-11 18:36:52 +05:30
Nabin Hait
804b4acb9b [fix] Issue fixed in C-Form related to field renaming 2015-06-11 16:56:36 +05:30
Nabin Hait
5c7557914b Removed BOM No from mandatory from Stock Entry against Production Order 2015-06-11 16:50:35 +05:30
Nabin Hait
381a9377d9 Merge branch 'develop' 2015-06-11 16:14:48 +05:30
Nabin Hait
9bdd1aa1ed bumped to version 5.0.21 2015-06-11 16:44:48 +06:00
Nabin Hait
d0df28bfa0 Merge pull request #3458 from nabinhait/develop
[fix] load tasks in project via __setup__ instead of onload function, to return tasks via get_doc
2015-06-11 16:12:05 +05:30
Nabin Hait
1966225450 [fix] load tasks in project via __setup__ instead of onload function, to return tasks via get_doc 2015-06-11 15:31:47 +05:30
Nabin Hait
4cee27eec0 Merge pull request #3446 from anandpdoshi/anand-june-9
POS - search by Item Group
2015-06-10 18:42:14 +05:30
Nabin Hait
c7d4eaee79 Merge pull request #3442 from nabinhait/develop
fixes in stock entry and report
2015-06-10 18:40:42 +05:30
Nabin Hait
43c1a9b502 [fix] Quote url for item image in product listing page 2015-06-10 18:23:17 +05:30
Nabin Hait
b937fac3ce [report] Warehouse column added in 'Ordered Items to be Delivered' report 2015-06-10 18:21:57 +05:30
Nabin Hait
53d94996ad [fix] Query for Against Journal Entry 2015-06-10 18:20:18 +05:30
Anand Doshi
26f6752c1e POS - search by Item Group 2015-06-09 16:33:46 -04:00
Nabin Hait
bb429745c0 [fix] Blank option in naming series 2015-06-09 18:59:51 +05:30
Nabin Hait
909f0c38f1 [report][enhancement] Payment period based on invoice date: show party columns and filter based on party 2015-06-09 18:42:52 +05:30
Nabin Hait
a790ba05f4 [fix] Item name, description should not be overwritten on saving of stock entry 2015-06-09 18:42:52 +05:30
Rushabh Mehta
9624bac3cf [fix] create SMS Log 2015-05-20 15:48:58 +05:30
298 changed files with 6537 additions and 4842 deletions

View File

@@ -1,5 +1,9 @@
# Contributing to Frappe / ERPNext
## Questions
If you have questions on how to use ERPNext or want help in customization or debugging of your scripts, please post on https://discuss.frappe.io. This is only for bug reports and feature requests.
## Reporting issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.

View File

@@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = '5.0.20'
__version__ = '5.3.0'

View File

@@ -35,7 +35,7 @@
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
"search_index": 0
},
{
"default": "0",
@@ -44,7 +44,7 @@
"label": "Is Group",
"permlevel": 0,
"precision": "",
"search_index": 1
"search_index": 0
},
{
"fieldname": "company",
@@ -57,7 +57,7 @@
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
"search_index": 0
},
{
"fieldname": "root_type",
@@ -147,7 +147,8 @@
"label": "Lft",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "rgt",
@@ -156,7 +157,8 @@
"label": "Rgt",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "old_parent",
@@ -171,7 +173,7 @@
"icon": "icon-money",
"idx": 1,
"in_create": 0,
"modified": "2015-05-28 14:10:40.606010",
"modified": "2015-07-20 03:54:14.297995",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@@ -255,5 +257,5 @@
"write": 1
}
],
"search_fields": "is_group"
"search_fields": ""
}

View File

@@ -49,7 +49,7 @@ class Account(Document):
self.root_type = par.root_type
def validate_root_details(self):
#does not exists parent
# does not exists parent
if frappe.db.exists("Account", self.name):
if not frappe.db.get_value("Account", self.name, "parent_account"):
throw(_("Root cannot be edited."))

View File

@@ -38,12 +38,19 @@
"label": "Credit Controller",
"options": "Role",
"permlevel": 0
},
{
"fieldname": "check_supplier_invoice_uniqueness",
"fieldtype": "Check",
"label": "Check Supplier Invoice Number Uniqueness",
"permlevel": 0,
"precision": ""
}
],
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"modified": "2015-02-05 05:11:34.163902",
"modified": "2015-07-14 00:51:48.095525",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -54,7 +54,7 @@ class CForm(Document):
frappe.throw(_("Please enter atleast 1 invoice in the table"))
def set_total_invoiced_amount(self):
total = sum([flt(d.base_grand_total) for d in self.get('invoices')])
total = sum([flt(d.grand_total) for d in self.get('invoices')])
frappe.db.set(self, 'total_invoiced_amount', total)
def get_invoice_details(self, invoice_no):

View File

@@ -17,7 +17,7 @@ erpnext.accounts.CostCenterController = frappe.ui.form.Controller.extend({
return {
filters:[
['Account', 'company', '=', me.frm.doc.company],
['Account', 'report_type', '=', 'Profit and Loss'],
['Account', 'root_type', '=', 'Expense'],
['Account', 'is_group', '=', '0'],
]
}

View File

@@ -66,7 +66,7 @@
"precision": ""
},
{
"description": "Define Budget for this Cost Center. To set budget action, see <a href=\"#!List/Company\">Company Master</a>",
"description": "Define Budget for this Cost Center. To set budget action, see \"Company List\"",
"fieldname": "sb1",
"fieldtype": "Section Break",
"label": "Budget",
@@ -139,7 +139,7 @@
"icon": "icon-money",
"idx": 1,
"in_create": 0,
"modified": "2015-04-23 02:54:26.934607",
"modified": "2015-07-13 05:28:25.504801",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@@ -189,8 +189,8 @@
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Material User"
"role": "Stock User"
}
],
"search_fields": "parent_cost_center, is_group"
}
}

View File

@@ -3,9 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe import _
from frappe.utils.nestedset import NestedSet
class CostCenter(NestedSet):
@@ -14,18 +12,46 @@ class CostCenter(NestedSet):
def autoname(self):
self.name = self.cost_center_name.strip() + ' - ' + \
frappe.db.get_value("Company", self.company, "abbr")
def validate(self):
self.validate_mandatory()
self.validate_accounts()
def validate_mandatory(self):
if self.cost_center_name != self.company and not self.parent_cost_center:
msgprint(_("Please enter parent cost center"), raise_exception=1)
frappe.throw(_("Please enter parent cost center"))
elif self.cost_center_name == self.company and self.parent_cost_center:
msgprint(_("Root cannot have a parent cost center"), raise_exception=1)
frappe.throw(_("Root cannot have a parent cost center"))
def validate_accounts(self):
if self.is_group==1 and self.get("budgets"):
frappe.throw(_("Budget cannot be set for Group Cost Center"))
check_acc_list = []
for d in self.get('budgets'):
if d.account:
account_details = frappe.db.get_value("Account", d.account,
["is_group", "company", "root_type"], as_dict=1)
if account_details.is_group:
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
elif account_details.company != self.company:
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
elif account_details.root_type != "Expense":
frappe.throw(_("Budget cannot be assigned against {0}, as it's not an Expense account")
.format(d.account))
if [d.account, d.fiscal_year] in check_acc_list:
frappe.throw(_("Account {0} has been entered more than once for fiscal year {1}")
.format(d.account, d.fiscal_year))
else:
check_acc_list.append([d.account, d.fiscal_year])
def convert_group_to_ledger(self):
if self.check_if_child_exists():
msgprint(_("Cannot convert Cost Center to ledger as it has child nodes"), raise_exception=1)
frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes"))
elif self.check_gle_exists():
msgprint(_("Cost Center with existing transactions can not be converted to ledger"), raise_exception=1)
frappe.throw(_("Cost Center with existing transactions can not be converted to ledger"))
else:
self.is_group = 0
self.save()
@@ -33,7 +59,7 @@ class CostCenter(NestedSet):
def convert_ledger_to_group(self):
if self.check_gle_exists():
msgprint(_("Cost Center with existing transactions can not be converted to group"), raise_exception=1)
frappe.throw(_("Cost Center with existing transactions can not be converted to group"))
else:
self.is_group = 1
self.save()
@@ -46,21 +72,6 @@ class CostCenter(NestedSet):
return frappe.db.sql("select name from `tabCost Center` where \
parent_cost_center = %s and docstatus != 2", self.name)
def validate_budget_details(self):
check_acc_list = []
for d in self.get('budgets'):
if self.is_group==1:
msgprint(_("Budget cannot be set for Group Cost Centers"), raise_exception=1)
if [d.account, d.fiscal_year] in check_acc_list:
msgprint(_("Account {0} has been entered more than once for fiscal year {1}").format(d.account, d.fiscal_year), raise_exception=1)
else:
check_acc_list.append([d.account, d.fiscal_year])
def validate(self):
self.validate_mandatory()
self.validate_budget_details()
def before_rename(self, olddn, newdn, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr

View File

@@ -56,7 +56,7 @@
],
"icon": "icon-calendar",
"idx": 1,
"modified": "2015-04-18 07:33:23.922518",
"modified": "2015-07-13 05:28:27.745408",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Fiscal Year",
@@ -78,11 +78,63 @@
{
"apply_user_permissions": 1,
"delete": 0,
"email": 1,
"email": 0,
"permlevel": 0,
"print": 1,
"print": 0,
"read": 1,
"role": "All"
"role": "Sales User"
},
{
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Purchase User",
"share": 0,
"write": 0
},
{
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts User",
"share": 0,
"write": 0
},
{
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Stock User",
"share": 0,
"write": 0
},
{
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Employee",
"share": 0,
"write": 0
}
],
"sort_field": "name",

View File

@@ -48,7 +48,8 @@
"fieldtype": "Dynamic Link",
"label": "Party",
"options": "party_type",
"permlevel": 0
"permlevel": 0,
"search_index": 1
},
{
"fieldname": "cost_center",
@@ -192,7 +193,7 @@
"icon": "icon-list",
"idx": 1,
"in_create": 1,
"modified": "2015-04-27 20:32:48.246818",
"modified": "2015-07-09 15:51:04.986518",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@@ -224,6 +225,19 @@
"role": "Accounts Manager",
"submit": 0,
"write": 0
},
{
"create": 0,
"delete": 0,
"email": 0,
"export": 1,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 1,
"role": "Auditor",
"share": 0,
"write": 0
}
],
"search_fields": "voucher_no,account,posting_date,against_voucher",

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, fmt_money, getdate, formatdate
from frappe.utils import flt, fmt_money, getdate, formatdate, cstr, cint
from frappe import _
from frappe.model.document import Document
@@ -118,7 +118,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry`
where against_voucher_type=%s and against_voucher=%s
and account = %s and party_type=%s and party=%s""",
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s""",
(against_voucher_type, against_voucher, account, party_type, party))[0][0] or 0.0)
if against_voucher_type == 'Purchase Invoice':
@@ -127,8 +127,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
against_voucher_amount = flt(frappe.db.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
and account = %s and party_type=%s and party=%s and ifnull(against_voucher, '') = ''""",
(against_voucher, account, party_type, party))[0][0])
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s
and ifnull(against_voucher, '') = ''""",
(against_voucher, account, cstr(party_type), cstr(party)))[0][0])
if not against_voucher_amount:
frappe.throw(_("Against Journal Entry {0} is already adjusted against some other voucher")
@@ -138,9 +139,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
if against_voucher_amount < 0:
bal = -bal
# Validation : Outstanding can not be negative
if bal < 0 and not on_cancel:
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
# Validation : Outstanding can not be negative for JV
if bal < 0 and not on_cancel:
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
# Update outstanding amt on against voucher
if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
@@ -157,3 +158,22 @@ def validate_frozen_account(account, adv_adj=None):
frappe.throw(_("Account {0} is frozen").format(account))
elif frozen_accounts_modifier not in frappe.get_roles():
frappe.throw(_("Not authorized to edit frozen Account {0}").format(account))
def update_against_account(voucher_type, voucher_no):
entries = frappe.db.get_all("GL Entry",
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
fields=["name", "party", "against", "debit", "credit", "account"])
accounts_debited, accounts_credited = [], []
for d in entries:
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
for d in entries:
if flt(d.debit > 0):
new_against = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0):
new_against = ", ".join(list(set(accounts_debited)))
if d.against != new_against:
frappe.db.set_value("GL Entry", d.name, "against", new_against)

View File

@@ -109,7 +109,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
against_jv: function(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) {
if (d.against_jv && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding('Journal Entry', d.against_jv, d);
}
},
@@ -119,7 +119,8 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
var args = {
"doctype": doctype,
"docname": docname,
"party": child.party
"party": child.party,
"account": child.account
}
return this.frm.call({

View File

@@ -53,7 +53,7 @@
"fieldname": "posting_date",
"fieldtype": "Date",
"in_filter": 1,
"in_list_view": 1,
"in_list_view": 0,
"label": "Posting Date",
"no_copy": 1,
"oldfieldname": "posting_date",
@@ -310,7 +310,7 @@
"depends_on": "eval:doc.voucher_type == 'Write Off Entry'",
"fieldname": "write_off_amount",
"fieldtype": "Currency",
"label": "Write Off Amount <=",
"label": "Write Off Amount",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
@@ -445,7 +445,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2015-04-27 20:32:31.655580",
"modified": "2015-06-29 15:28:12.529019",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
@@ -503,4 +503,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title"
}
}

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, date_diff
from frappe import msgprint, _, scrub
from erpnext.setup.utils import get_company_currency
from erpnext.controllers.accounts_controller import AccountsController
@@ -35,7 +35,7 @@ class JournalEntry(AccountsController):
self.set_print_format_fields()
self.validate_against_sales_order()
self.validate_against_purchase_order()
self.check_credit_days()
self.check_due_date()
self.validate_expense_claim()
self.validate_credit_debit_note()
self.validate_empty_accounts_table()
@@ -81,30 +81,28 @@ class JournalEntry(AccountsController):
frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
def check_credit_limit(self):
customers = list(set([d.party for d in self.get("accounts")
customers = list(set([d.party for d in self.get("accounts")
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
if customers:
from erpnext.selling.doctype.customer.customer import check_credit_limit
for customer in customers:
check_credit_limit(customer, self.company)
def check_credit_days(self):
from erpnext.accounts.party import get_credit_days
posting_date = None
def check_due_date(self):
if self.cheque_date:
for d in self.get("accounts"):
if d.party_type and d.party and d.get("credit" if d.party_type=="Customer" else "debit") > 0:
due_date = None
if d.against_invoice:
posting_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "posting_date")
due_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "due_date")
elif d.against_voucher:
posting_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "posting_date")
due_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "due_date")
credit_days = get_credit_days(d.party_type, d.party, self.company)
if posting_date and credit_days:
date_diff = (getdate(self.cheque_date) - getdate(posting_date)).days
if date_diff > flt(credit_days):
msgprint(_("Note: Reference Date exceeds allowed credit days by {0} days for {1} {2}")
.format(date_diff - flt(credit_days), d.party_type, d.party))
if due_date and getdate(self.cheque_date) > getdate(due_date):
diff = date_diff(self.cheque_date, due_date)
if diff > 0:
msgprint(_("Note: Reference Date exceeds invoice due date by {0} days for {1} {2}")
.format(diff, d.party_type, d.party))
def validate_cheque_info(self):
if self.voucher_type in ['Bank Entry']:
@@ -243,8 +241,8 @@ class JournalEntry(AccountsController):
def set_against_account(self):
accounts_debited, accounts_credited = [], []
for d in self.get("accounts"):
if flt(d.debit > 0): accounts_debited.append(d.account)
if flt(d.credit) > 0: accounts_credited.append(d.account)
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
for d in self.get("accounts"):
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
@@ -275,29 +273,27 @@ class JournalEntry(AccountsController):
else:
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
company_currency = get_company_currency(self.company)
for d in self.get('accounts'):
if d.against_invoice and d.credit:
currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
d.against_invoice))
if d.against_sales_order and d.credit:
currency = frappe.db.get_value("Sales Order", d.against_sales_order, "currency")
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
d.against_sales_order))
if d.against_voucher and d.debit:
bill_no = frappe.db.sql("""select bill_no, bill_date, currency
bill_no = frappe.db.sql("""select bill_no, bill_date
from `tabPurchase Invoice` where name=%s""", d.against_voucher)
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
not in ['na', 'not applicable', 'none']:
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=bill_no[0][2]), bill_no[0][0],
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=company_currency), bill_no[0][0],
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
if d.against_purchase_order and d.debit:
currency = frappe.db.get_value("Purchase Order", d.against_purchase_order, "currency")
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
d.against_purchase_order))
if self.user_remark:
@@ -428,7 +424,7 @@ class JournalEntry(AccountsController):
def validate_expense_claim(self):
for d in self.accounts:
if d.against_expense_claim:
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim",
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim",
d.against_expense_claim, ("total_sanctioned_amount", "total_amount_reimbursed"))
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
if d.debit > pending_amount:
@@ -458,11 +454,11 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
if voucher_type=="Bank Entry":
account = frappe.db.get_value("Company", company, "default_bank_account")
if not account:
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank"})
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
elif voucher_type=="Cash Entry":
account = frappe.db.get_value("Company", company, "default_cash_account")
if not account:
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash"})
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
if account:
return {
@@ -538,25 +534,25 @@ def get_opening_accounts(company):
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("party"):
return []
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s
where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = ''
and ifnull(jv_detail.against_jv, '') = '' )
and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield),
(filters["account"], filters["party"], "%{0}%".format(txt), start, page_len))
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
@frappe.whitelist()
def get_outstanding(args):
args = eval(args)
if args.get("doctype") == "Journal Entry" and args.get("party"):
if args.get("doctype") == "Journal Entry":
condition = " and party=%(party)s" if args.get("party") else ""
against_jv_amount = frappe.db.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabJournal Entry Account` where parent=%s and party=%s
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
and ifnull(against_invoice, '')='' and ifnull(against_voucher, '')=''
and ifnull(against_jv, '')=''""", (args['docname'], args['party']))
and ifnull(against_jv, '')=''""".format(condition), args)
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
if against_jv_amount > 0:

View File

@@ -77,6 +77,51 @@
"read_only": 0,
"reqd": 1
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"read_only": 0,
"reqd": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
"oldfieldname": "letter_head",
"oldfieldtype": "Select",
"options": "Letter Head",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
},
{
"fieldname": "tc_name",
"fieldtype": "Link",
"label": "Terms and Conditions",
"oldfieldname": "tc_name",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
"permlevel": 0,
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"in_filter": 0,
"label": "Print Heading",
"oldfieldname": "select_print_heading",
"oldfieldtype": "Select",
"options": "Print Heading",
"permlevel": 0,
"read_only": 0
},
{
"fieldname": "column_break0",
"fieldtype": "Column Break",
@@ -105,6 +150,14 @@
"read_only": 0,
"reqd": 0
},
{
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"label": "Mode of Payment",
"options": "Mode of Payment",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "cash_bank_account",
"fieldtype": "Link",
@@ -139,17 +192,6 @@
"read_only": 0,
"reqd": 0
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"read_only": 0,
"reqd": 0
},
{
"fieldname": "cost_center",
"fieldtype": "Link",
@@ -161,16 +203,6 @@
"read_only": 0,
"reqd": 1
},
{
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"label": "Taxes and Charges",
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Sales Taxes and Charges Template",
"permlevel": 0,
"read_only": 0
},
{
"fieldname": "write_off_account",
"fieldtype": "Link",
@@ -190,43 +222,19 @@
"reqd": 1
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"label": "Letter Head",
"oldfieldname": "letter_head",
"oldfieldtype": "Select",
"options": "Letter Head",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
},
{
"fieldname": "tc_name",
"fieldtype": "Link",
"label": "Terms and Conditions",
"oldfieldname": "tc_name",
"label": "Taxes and Charges",
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Terms and Conditions",
"permlevel": 0,
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"in_filter": 0,
"label": "Print Heading",
"oldfieldname": "select_print_heading",
"oldfieldtype": "Select",
"options": "Print Heading",
"options": "Sales Taxes and Charges Template",
"permlevel": 0,
"read_only": 0
}
],
"icon": "icon-cog",
"idx": 1,
"modified": "2015-05-20 05:38:44.482696",
"modified": "2015-07-07 08:56:04.381471",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -21,10 +21,11 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
// Show / Hide button
if(doc.docstatus==1 && doc.outstanding_amount > 0)
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry,
frappe.boot.doctype_icons["Journal Entry"]);
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry);
if(doc.docstatus==1) {
cur_frm.add_custom_button(__('Make Purchase Return'), this.make_purchase_return);
cur_frm.add_custom_button(__('View Ledger'), function() {
frappe.route_options = {
"voucher_no": doc.name,
@@ -34,7 +35,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
group_by_voucher: 0
};
frappe.set_route("query-report", "General Ledger");
}, "icon-table");
});
}
if(doc.docstatus===0) {
@@ -51,7 +52,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default");
});
cur_frm.add_custom_button(__('From Purchase Receipt'),
function() {
@@ -64,11 +65,11 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default");
});
}
},
supplier: function() {
var me = this;
if(this.frm.updating_party_details)
@@ -109,7 +110,14 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
$.each(this.frm.doc["items"] || [], function(i, row) {
if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
})
}
},
make_purchase_return: function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_purchase_return",
frm: cur_frm
})
},
});
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
@@ -224,3 +232,4 @@ cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
else
cur_frm.pformat.print_heading = __("Purchase Invoice");
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, formatdate, flt
from frappe.utils import cint, formatdate, flt, getdate
from frappe import msgprint, _, throw
from erpnext.setup.utils import get_company_currency
import frappe.defaults
@@ -37,13 +37,16 @@ class PurchaseInvoice(BuyingController):
super(PurchaseInvoice, self).validate()
self.po_required()
self.pr_required()
if not self.is_return:
self.po_required()
self.pr_required()
self.validate_supplier_invoice()
self.validate_advance_jv("advances", "purchase_order")
self.check_active_purchase_items()
self.check_conversion_rate()
self.validate_credit_to_acc()
self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
self.validate_advance_jv("advances", "purchase_order")
self.check_for_stopped_status()
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty")
@@ -70,8 +73,9 @@ class PurchaseInvoice(BuyingController):
super(PurchaseInvoice, self).set_missing_values(for_validate)
def get_advances(self):
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
if not self.is_return:
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
def check_active_purchase_items(self):
for d in self.get('items'):
@@ -87,9 +91,7 @@ class PurchaseInvoice(BuyingController):
throw(_("Conversion rate cannot be 0 or 1"))
def validate_credit_to_acc(self):
root_type, account_type = frappe.db.get_value("Account", self.credit_to, ["root_type", "account_type"])
if root_type != "Liability":
frappe.throw(_("Credit To account must be a liability account"))
account_type = frappe.db.get_value("Account", self.credit_to, "account_type")
if account_type != "Payable":
frappe.throw(_("Credit To account must be a Payable account"))
@@ -125,20 +127,11 @@ class PurchaseInvoice(BuyingController):
}
})
if cint(frappe.defaults.get_global_default('maintain_same_rate')):
super(PurchaseInvoice, self).validate_with_previous_doc({
"Purchase Order Item": {
"ref_dn_field": "po_detail",
"compare_fields": [["rate", "="]],
"is_child_table": True,
"allow_duplicate_prev_row_id": True
},
"Purchase Receipt Item": {
"ref_dn_field": "pr_detail",
"compare_fields": [["rate", "="]],
"is_child_table": True
}
})
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
self.validate_rate_with_reference_doc([
["Purchase Order", "purchase_order", "po_detail"],
["Purchase Receipt", "purchase_receipt", "pr_detail"]
])
def set_against_expense_account(self):
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
@@ -165,7 +158,7 @@ class PurchaseInvoice(BuyingController):
elif item.expense_account not in against_accounts:
# if no auto_accounting_for_stock or not a stock item
against_accounts.append(item.expense_account)
self.against_expense_account = ",".join(against_accounts)
def po_required(self):
@@ -236,9 +229,11 @@ class PurchaseInvoice(BuyingController):
# this sequence because outstanding may get -negative
self.make_gl_entries()
self.update_against_document_in_jv()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
if not self.is_return:
self.update_against_document_in_jv()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.update_project()
def make_gl_entries(self):
@@ -272,7 +267,7 @@ class PurchaseInvoice(BuyingController):
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.credit_to,
"against": self.supplier,
"debit": tax.add_deduct_tax == "Add" and tax.base_tax_amount_after_discount_amount or 0,
"credit": tax.add_deduct_tax == "Deduct" and tax.base_tax_amount_after_discount_amount or 0,
"remarks": self.remarks,
@@ -296,7 +291,7 @@ class PurchaseInvoice(BuyingController):
gl_entries.append(
self.get_gl_dict({
"account": item.expense_account,
"against": self.credit_to,
"against": self.supplier,
"debit": item.base_net_amount,
"remarks": self.remarks,
"cost_center": item.cost_center
@@ -316,7 +311,7 @@ class PurchaseInvoice(BuyingController):
gl_entries.append(
self.get_gl_dict({
"account": stock_received_but_not_billed,
"against": self.credit_to,
"against": self.supplier,
"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
"remarks": self.remarks or "Accounting Entry for Stock"
})
@@ -342,7 +337,7 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict({
"account": expenses_included_in_valuation,
"cost_center": cost_center,
"against": self.credit_to,
"against": self.supplier,
"credit": applicable_amount,
"remarks": self.remarks or "Accounting Entry for Stock"
})
@@ -356,7 +351,7 @@ class PurchaseInvoice(BuyingController):
gl_entries.append(
self.get_gl_dict({
"account": self.write_off_account,
"against": self.credit_to,
"against": self.supplier,
"credit": flt(self.write_off_amount),
"remarks": self.remarks,
"cost_center": self.write_off_cost_center
@@ -368,14 +363,15 @@ class PurchaseInvoice(BuyingController):
make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
def on_cancel(self):
from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
if not self.is_return:
from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.make_gl_entries_on_cancel()
self.update_project()
def update_project(self):
project_list = []
for d in self.items:
@@ -386,6 +382,17 @@ class PurchaseInvoice(BuyingController):
project.save()
project_list.append(d.project_name)
def validate_supplier_invoice(self):
if self.bill_date:
if getdate(self.bill_date) > getdate(self.posting_date):
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
if self.bill_no:
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no,
"fiscal_year": self.fiscal_year, "name": ("!=", self.name)})
if pi:
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
@frappe.whitelist()
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond
@@ -401,4 +408,9 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.company = '%(company)s'
and tabAccount.%(key)s LIKE '%(txt)s'
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
@frappe.whitelist()
def make_purchase_return(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)

View File

@@ -275,5 +275,58 @@ class TestPurchaseInvoice(unittest.TestCase):
purchase_invoice.cancel()
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 0)
def test_return_purchase_invoice(self):
set_perpetual_inventory()
pi = make_purchase_invoice()
return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2)
# check gl entries for return
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account desc""", ("Purchase Invoice", return_pi.name), as_dict=1)
self.assertTrue(gl_entries)
expected_values = {
"Creditors - _TC": [100.0, 0.0],
"Stock Received But Not Billed - _TC": [0.0, 100.0],
}
for gle in gl_entries:
self.assertEquals(expected_values[gle.account][0], gle.debit)
self.assertEquals(expected_values[gle.account][1], gle.credit)
set_perpetual_inventory(0)
def make_purchase_invoice(**args):
pi = frappe.new_doc("Purchase Invoice")
args = frappe._dict(args)
if args.posting_date:
pi.posting_date = args.posting_date
if args.posting_time:
pi.posting_time = args.posting_time
pi.company = args.company or "_Test Company"
pi.supplier = args.supplier or "_Test Supplier"
pi.currency = args.currency or "INR"
pi.is_return = args.is_return
pi.return_against = args.return_against
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 5,
"rate": args.rate or 50,
"conversion_factor": 1.0,
"serial_no": args.serial_no,
"stock_uom": "_Test UOM"
})
if not args.do_not_save:
pi.insert()
if not args.do_not_submit:
pi.submit()
return pi
test_records = frappe.get_test_records('Purchase Invoice')

View File

@@ -49,6 +49,23 @@
"read_only": 0,
"width": "300px"
},
{
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
"label": "Image",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "image_view",
"fieldtype": "Image",
"label": "Image View",
"options": "image",
"permlevel": 0,
"precision": "",
"print_hide": 1
},
{
"fieldname": "quantity_and_rate",
"fieldtype": "Section Break",
@@ -452,7 +469,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-06-02 14:18:56.294949",
"modified": "2015-07-02 03:00:44.496683",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -4,10 +4,9 @@
from __future__ import unicode_literals
from frappe.model.document import Document
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
from erpnext.accounts.doctype.sales_taxes_and_charges_template.sales_taxes_and_charges_template \
import valdiate_taxes_and_charges_template
class PurchaseTaxesandChargesTemplate(Document):
def validate(self):
for tax in self.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, self)
valdiate_taxes_and_charges_template(self)

View File

@@ -7,6 +7,7 @@ import frappe
@frappe.whitelist()
def get_items(price_list, sales_or_purchase, item=None):
condition = ""
order_by = ""
args = {"price_list": price_list}
if sales_or_purchase == "Sales":
@@ -30,16 +31,25 @@ def get_items(price_list, sales_or_purchase, item=None):
item_code[0]["barcode"] = item
return item_code
condition += " and (CONCAT(i.name, i.item_name) like %(name)s or (i.variant_of like %(name)s))"
args["name"] = "%%%s%%" % item
condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))"
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999),
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
args["name"] = "%%%s%%" % frappe.db.escape(item)
args["_name"] = item.replace("%", "")
# locate function is used to sort by closest match from the beginning of the value
return frappe.db.sql("""select i.name, i.item_name, i.image,
item_det.price_list_rate, item_det.currency
from `tabItem` i LEFT JOIN
(select item_code, price_list_rate, currency from
`tabItem Price` where price_list=%s) item_det
`tabItem Price` where price_list=%(price_list)s) item_det
ON
(item_det.item_code=i.name or item_det.item_code=i.variant_of)
where
ifnull(i.has_variants, 0) = 0 and
%s""" % ('%(price_list)s', condition), args, as_dict=1)
{condition}
order by
{order_by}
i.name""".format(condition=condition, order_by=order_by), args, as_dict=1)

View File

@@ -40,7 +40,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this._super();
cur_frm.dashboard.reset();
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
if(doc.docstatus==1) {
cur_frm.add_custom_button('View Ledger', function() {
frappe.route_options = {
@@ -51,10 +53,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
group_by_voucher: 0
};
frappe.set_route("query-report", "General Ledger");
}, "icon-table");
// var percent_paid = cint(flt(doc.base_grand_total - doc.outstanding_amount) / flt(doc.base_grand_total) * 100);
// cur_frm.dashboard.add_progress(percent_paid + "% Paid", percent_paid);
});
if(cint(doc.update_stock)!=1) {
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
@@ -65,13 +64,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
});
if(!from_delivery_note) {
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'])
}
}
if(doc.outstanding_amount!=0) {
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry, "icon-money");
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry);
}
cur_frm.add_custom_button(__('Make Sales Return'), this.make_sales_return);
}
// Show buttons only when pos view is active
@@ -205,8 +206,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
items_on_form_rendered: function() {
erpnext.setup_serial_no();
},
make_sales_return: function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
frm: cur_frm
})
}
});
// for backward compatibility: combine new and previous states
@@ -283,16 +290,6 @@ cur_frm.cscript.make_bank_entry = function() {
});
}
cur_frm.fields_dict.debit_to.get_query = function(doc) {
return{
filters: {
'report_type': 'Balance Sheet',
'is_group': 0,
'company': doc.company
}
}
}
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
return {
filters: [
@@ -369,15 +366,15 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
}
cur_frm.cscript.income_account = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "income_account");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "income_account");
}
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "expense_account");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
}
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "cost_center");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
@@ -392,8 +389,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
}
}
cur_frm.set_query("debit_to", function(doc) {
return{
filters: [
@@ -401,4 +396,4 @@ cur_frm.set_query("debit_to", function(doc) {
['Account', 'account_type', '=', 'Receivable']
]
}
});
});

View File

@@ -21,7 +21,7 @@
"no_copy": 1,
"oldfieldname": "naming_series",
"oldfieldtype": "Select",
"options": "SINV-",
"options": "SINV-\nSINV-RET-",
"permlevel": 0,
"print_hide": 1,
"read_only": 0,
@@ -38,7 +38,8 @@
"options": "Customer",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
"read_only": 0,
"search_index": 1
},
{
"depends_on": "customer",
@@ -46,7 +47,7 @@
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 0,
"label": "Name",
"label": "Customer Name",
"oldfieldname": "customer_name",
"oldfieldtype": "Data",
"permlevel": 0,
@@ -155,7 +156,7 @@
"oldfieldtype": "Date",
"permlevel": 0,
"read_only": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0
},
{
@@ -168,6 +169,28 @@
"print_hide": 1,
"read_only": 0
},
{
"fieldname": "is_return",
"fieldtype": "Check",
"label": "Is Return",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "is_return",
"fieldname": "return_against",
"fieldtype": "Link",
"label": "Return Against Sales Invoice",
"no_copy": 0,
"options": "Sales Invoice",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "shipping_address_name",
"fieldtype": "Link",
@@ -321,9 +344,9 @@
"read_only": 0
},
{
"fieldname": "sales_bom_help",
"fieldname": "product_bundle_help",
"fieldtype": "HTML",
"label": "Sales BOM Help",
"label": "Product Bundle Help",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
@@ -502,7 +525,7 @@
{
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount (Company Currency)",
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
@@ -604,7 +627,7 @@
"label": "Total Advance",
"oldfieldname": "total_advance",
"oldfieldtype": "Currency",
"options": "",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
@@ -617,7 +640,7 @@
"no_copy": 1,
"oldfieldname": "outstanding_amount",
"oldfieldtype": "Currency",
"options": "currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
@@ -670,7 +693,7 @@
"no_copy": 1,
"oldfieldname": "paid_amount",
"oldfieldtype": "Currency",
"options": "currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
@@ -710,7 +733,7 @@
"fieldtype": "Currency",
"label": "Write Off Amount",
"no_copy": 1,
"options": "currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 0
@@ -880,7 +903,7 @@
"options": "Project",
"permlevel": 0,
"read_only": 0,
"search_index": 1
"search_index": 0
},
{
"depends_on": "eval:doc.source == 'Campaign'",
@@ -1226,6 +1249,15 @@
"print_hide": 1,
"read_only": 0
},
{
"depends_on": "eval:doc.is_recurring==1",
"fieldname": "recurring_print_format",
"fieldtype": "Link",
"label": "Recurring Print Format",
"options": "Print Format",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "against_income_account",
"fieldtype": "Small Text",
@@ -1243,7 +1275,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2015-05-27 02:48:02.897865",
"modified": "2015-07-24 11:48:07.544569",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -65,8 +65,7 @@ class SalesInvoice(SellingController):
self.set_against_income_account()
self.validate_c_form()
self.validate_time_logs_are_submitted()
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
"items")
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
def on_submit(self):
super(SalesInvoice, self).on_submit()
@@ -81,14 +80,16 @@ class SalesInvoice(SellingController):
self.check_prev_docstatus()
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.check_credit_limit()
if not self.is_return:
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.check_credit_limit()
# this sequence because outstanding may get -ve
self.make_gl_entries()
if not cint(self.is_pos) == 1:
if not cint(self.is_pos) == 1 and not self.is_return:
self.update_against_document_in_jv()
self.update_time_log_batch(self.name)
@@ -101,13 +102,15 @@ class SalesInvoice(SellingController):
self.update_stock_ledger()
self.check_stop_sales_order("sales_order")
from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doctype, self.name, "against_invoice")
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
if not self.is_return:
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.validate_c_form_on_cancel()
self.make_gl_entries_on_cancel()
@@ -139,7 +142,7 @@ class SalesInvoice(SellingController):
if not self.debit_to:
self.debit_to = get_party_account(self.company, self.customer, "Customer")
if not self.due_date:
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
super(SalesInvoice, self).set_missing_values(for_validate)
@@ -170,6 +173,7 @@ class SalesInvoice(SellingController):
if pos:
if not for_validate and not self.customer:
self.customer = pos.customer
self.mode_of_payment = pos.mode_of_payment
# self.set_customer_defaults()
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
@@ -199,8 +203,9 @@ class SalesInvoice(SellingController):
self.set_taxes()
def get_advances(self):
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
"Sales Invoice Advance", "advances", "credit", "sales_order")
if not self.is_return:
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
"Sales Invoice Advance", "advances", "credit", "sales_order")
def get_company_abbr(self):
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
@@ -236,9 +241,7 @@ class SalesInvoice(SellingController):
reconcile_against_document(lst)
def validate_debit_to_acc(self):
root_type, account_type = frappe.db.get_value("Account", self.debit_to, ["root_type", "account_type"])
if root_type != "Asset":
frappe.throw(_("Debit To account must be a liability account"))
account_type = frappe.db.get_value("Account", self.debit_to, "account_type")
if account_type != "Receivable":
frappe.throw(_("Debit To account must be a Receivable account"))
@@ -266,20 +269,11 @@ class SalesInvoice(SellingController):
},
})
if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
super(SalesInvoice, self).validate_with_previous_doc({
"Sales Order Item": {
"ref_dn_field": "so_detail",
"compare_fields": [["rate", "="]],
"is_child_table": True,
"allow_duplicate_prev_row_id": True
},
"Delivery Note Item": {
"ref_dn_field": "dn_detail",
"compare_fields": [["rate", "="]],
"is_child_table": True
}
})
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
self.validate_rate_with_reference_doc([
["Sales Order", "sales_order", "so_detail"],
["Delivery Note", "delivery_note", "dn_detail"]
])
def set_against_income_account(self):
"""Set against account for debit to account"""
@@ -296,6 +290,8 @@ class SalesInvoice(SellingController):
def so_dn_required(self):
"""check in manage account if sales order / delivery note required or not."""
if self.is_return:
return
dic = {'Sales Order':'so_required','Delivery Note':'dn_required'}
for i in dic:
if frappe.db.get_value('Selling Settings', None, dic[i]) == 'Yes':
@@ -430,13 +426,16 @@ class SalesInvoice(SellingController):
def update_stock_ledger(self):
sl_entries = []
for d in self.get_item_list():
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" \
and d.warehouse:
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
incoming_rate = 0
if cint(self.is_return) and self.return_against and self.docstatus==1:
incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
sl_entries.append(self.get_sl_entries(d, {
"actual_qty": -1*flt(d.qty),
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom")
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
"incoming_rate": incoming_rate
}))
self.make_sl_entries(sl_entries)
def make_gl_entries(self, repost_future_gle=True):
@@ -446,8 +445,7 @@ class SalesInvoice(SellingController):
from erpnext.accounts.general_ledger import make_gl_entries
# if POS and amount is written off, there's no outstanding and hence no need to update it
update_outstanding = cint(self.is_pos) and self.write_off_account \
and 'No' or 'Yes'
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account) else "Yes"
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
update_outstanding=update_outstanding, merge_entries=False)
@@ -495,7 +493,7 @@ class SalesInvoice(SellingController):
"against": self.against_income_account,
"debit": self.base_grand_total,
"remarks": self.remarks,
"against_voucher": self.name,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
})
)
@@ -506,7 +504,7 @@ class SalesInvoice(SellingController):
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.debit_to,
"against": self.customer,
"credit": flt(tax.base_tax_amount_after_discount_amount),
"remarks": self.remarks,
"cost_center": tax.cost_center
@@ -520,7 +518,7 @@ class SalesInvoice(SellingController):
gl_entries.append(
self.get_gl_dict({
"account": item.income_account,
"against": self.debit_to,
"against": self.customer,
"credit": item.base_net_amount,
"remarks": self.remarks,
"cost_center": item.cost_center
@@ -530,7 +528,6 @@ class SalesInvoice(SellingController):
# expense account gl entries
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
and cint(self.update_stock):
gl_entries += super(SalesInvoice, self).get_gl_entries()
def make_pos_gl_entries(self, gl_entries):
@@ -544,14 +541,14 @@ class SalesInvoice(SellingController):
"against": self.cash_bank_account,
"credit": self.paid_amount,
"remarks": self.remarks,
"against_voucher": self.name,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
})
)
gl_entries.append(
self.get_gl_dict({
"account": self.cash_bank_account,
"against": self.debit_to,
"against": self.customer,
"debit": self.paid_amount,
"remarks": self.remarks,
})
@@ -568,14 +565,14 @@ class SalesInvoice(SellingController):
"against": self.write_off_account,
"credit": self.write_off_amount,
"remarks": self.remarks,
"against_voucher": self.name,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype,
})
)
gl_entries.append(
self.get_gl_dict({
"account": self.write_off_account,
"against": self.debit_to,
"against": self.customer,
"debit": self.write_off_amount,
"remarks": self.remarks,
"cost_center": self.write_off_cost_center
@@ -590,7 +587,7 @@ def get_list_context(context=None):
@frappe.whitelist()
def get_bank_cash_account(mode_of_payment, company):
account = frappe.db.get_value("Mode of Payment Account",
account = frappe.db.get_value("Mode of Payment Account",
{"parent": mode_of_payment, "company": company}, "default_account")
if not account:
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
@@ -614,7 +611,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.company = '%(company)s'
and tabAccount.%(key)s LIKE '%(txt)s'
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
@frappe.whitelist()
def make_delivery_note(source_name, target_doc=None):
@@ -662,3 +659,9 @@ def make_delivery_note(source_name, target_doc=None):
}, target_doc, set_missing_values)
return doclist
@frappe.whitelist()
def make_sales_return(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Sales Invoice", source_name, target_doc)

View File

@@ -4,10 +4,10 @@ from __future__ import unicode_literals
import frappe
import unittest, copy
import time
from erpnext.accounts.utils import get_stock_and_account_difference
from frappe.utils import nowdate, add_days, flt
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
class TestSalesInvoice(unittest.TestCase):
@@ -756,20 +756,84 @@ class TestSalesInvoice(unittest.TestCase):
# hack! because stock ledger entires are already inserted and are not rolled back!
self.assertRaises(SerialNoDuplicateError, si.cancel)
def test_invoice_due_date_against_customers_credit_days(self):
# set customer's credit days
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Fixed Days")
frappe.db.set_value("Customer", "_Test Customer", "credit_days", 10)
si = create_sales_invoice()
self.assertEqual(si.due_date, add_days(nowdate(), 10))
# set customer's credit days is last day of the next month
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Last Day of the Next Month")
si1 = create_sales_invoice(posting_date="2015-07-05")
self.assertEqual(si1.due_date, "2015-08-31")
def test_return_sales_invoice(self):
set_perpetual_inventory()
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
actual_qty_0 = get_qty_after_transaction()
si = create_sales_invoice(qty=5, rate=500, update_stock=1)
actual_qty_1 = get_qty_after_transaction()
self.assertEquals(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate
outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Sales Invoice",
"voucher_no": si.name}, "stock_value_difference") / 5
# return entry
si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
actual_qty_2 = get_qty_after_transaction()
self.assertEquals(actual_qty_1 + 2, actual_qty_2)
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Sales Invoice", "voucher_no": si1.name},
["incoming_rate", "stock_value_difference"])
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
# Check gl entry
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
"voucher_no": si1.name, "account": "_Test Warehouse - _TC"}, "debit")
self.assertEquals(gle_warehouse_amount, stock_value_difference)
party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
"voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
self.assertEqual(party_credited, 1000)
# Check outstanding amount
self.assertFalse(si1.outstanding_amount)
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
set_perpetual_inventory(0)
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
if args.posting_date:
si.posting_date = args.posting_date
if args.posting_time:
si.posting_time = args.posting_time
si.posting_date = args.posting_date or nowdate()
si.company = args.company or "_Test Company"
si.customer = args.customer or "_Test Customer"
si.debit_to = args.debit_to or "Debtors - _TC"
si.update_stock = args.update_stock
si.is_pos = args.is_pos
si.is_return = args.is_return
si.return_against = args.return_against
si.currency="INR"
si.conversion_rate = 1
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",

View File

@@ -68,6 +68,23 @@
"reqd": 1,
"width": "200px"
},
{
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
"label": "Image",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "image_view",
"fieldtype": "Image",
"label": "Image View",
"options": "image",
"permlevel": 0,
"precision": "",
"print_hide": 1
},
{
"fieldname": "quantity_and_rate",
"fieldtype": "Section Break",
@@ -505,7 +522,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-06-02 14:18:45.176726",
"modified": "2015-07-02 02:59:08.413213",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -5,21 +5,25 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
from frappe.utils.nestedset import get_root_of
class SalesTaxesandChargesTemplate(Document):
def validate(self):
if self.is_default == 1:
frappe.db.sql("""update `tabSales Taxes and Charges Template`
set is_default = 0
where ifnull(is_default,0) = 1
and name != %s and company = %s""",
(self.name, self.company))
valdiate_taxes_and_charges_template(self)
# at least one territory
self.validate_table_has_rows("territories")
def valdiate_taxes_and_charges_template(doc):
if not doc.is_default and not frappe.get_all(doc.doctype, filters={"is_default": 1}):
doc.is_default = 1
for tax in self.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, self)
if doc.is_default == 1:
frappe.db.sql("""update `tab{0}` set is_default = 0
where ifnull(is_default,0) = 1 and name != %s and company = %s""".format(doc.doctype),
(doc.name, doc.company))
if doc.meta.get_field("territories"):
if not doc.territories:
doc.append("territories", {"territory": get_root_of("Territory") })
for tax in doc.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, doc)

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cstr
from frappe.utils import flt, cstr, cint
from frappe import _
from frappe.model.meta import get_field_precision
from erpnext.accounts.utils import validate_expense_against_budget
@@ -82,14 +82,15 @@ def make_entry(args, adv_adj, update_outstanding):
gle.submit()
def validate_account_for_auto_accounting_for_stock(gl_map):
if gl_map[0].voucher_type=="Journal Entry":
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
and gl_map[0].voucher_type=="Journal Entry":
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
for entry in gl_map:
if entry.account in aii_accounts:
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(entry.account), StockAccountInvalidTransaction)
for entry in gl_map:
if entry.account in aii_accounts:
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(entry.account), StockAccountInvalidTransaction)
def round_off_debit_credit(gl_map):
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),

View File

@@ -4,9 +4,10 @@
from __future__ import unicode_literals
import frappe
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.utils import add_days, getdate, formatdate, flt
from frappe.utils import add_days, getdate, formatdate, flt, get_first_day, date_diff, nowdate
from erpnext.utilities.doctype.address.address import get_address_display
from erpnext.utilities.doctype.contact.contact import get_contact_details
@@ -73,9 +74,17 @@ def set_contact_details(out, party, party_type):
{party_type.lower(): party.name, "is_primary_contact":1}, "name")
if not out.contact_person:
return
out.update(get_contact_details(out.contact_person))
out.update({
"contact_person": None,
"contact_display": None,
"contact_email": None,
"contact_mobile": None,
"contact_phone": None,
"contact_designation": None,
"contact_department": None
})
else:
out.update(get_contact_details(out.contact_person))
def set_other_values(out, party, party_type):
# copy
@@ -158,43 +167,54 @@ def get_party_account(company, party, party_type):
return account
@frappe.whitelist()
def get_due_date(posting_date, party_type, party, company):
"""Set Due Date = Posting Date + Credit Days"""
due_date = None
if posting_date:
credit_days = get_credit_days(party_type, party, company)
due_date = add_days(posting_date, credit_days) if credit_days else posting_date
if posting_date and party:
due_date = posting_date
if party_type=="Customer":
credit_days_based_on, credit_days = get_credit_days(party_type, party, company)
if credit_days_based_on == "Fixed Days" and credit_days:
due_date = add_days(posting_date, credit_days)
elif credit_days_based_on == "Last Day of the Next Month":
due_date = (get_first_day(posting_date, 0, 2) + datetime.timedelta(-1)).strftime("%Y-%m-%d")
else:
credit_days = get_credit_days(party_type, party, company)
if credit_days:
due_date = add_days(posting_date, credit_days)
return due_date
def get_credit_days(party_type, party, company):
if not party:
return None
party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
credit_days, party_group = frappe.db.get_value(party_type, party, ["credit_days", frappe.scrub(party_group_doctype)])
if not credit_days:
credit_days = frappe.db.get_value(party_group_doctype, party_group, "credit_days") or \
frappe.db.get_value("Company", company, "credit_days")
return credit_days
def validate_due_date(posting_date, due_date, party_type, party, company):
credit_days = get_credit_days(party_type, party, company)
posting_date, due_date = getdate(posting_date), getdate(due_date)
diff = (due_date - posting_date).days
if diff < 0:
frappe.throw(_("Due Date cannot be before Posting Date"))
elif credit_days is not None and diff > flt(credit_days):
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
"credit_controller") in frappe.get_roles()
if is_credit_controller:
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
.format(diff - flt(credit_days)))
if party_type and party:
if party_type == "Customer":
credit_days_based_on, credit_days, customer_group = \
frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "customer_group"])
if not credit_days_based_on:
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"])
return credit_days_based_on, credit_days
else:
max_due_date = formatdate(add_days(posting_date, credit_days))
frappe.throw(_("Due / Reference Date cannot be after {0}").format(max_due_date))
credit_days, supplier_type = frappe.db.get_value(party_type, party, ["credit_days", "supplier_type"])
if not credit_days:
credit_days = frappe.db.get_value("Supplier Type", supplier_type, "credit_days") \
or frappe.db.get_value("Company", company, "credit_days")
return credit_days
def validate_due_date(posting_date, due_date, party_type, party, company):
if getdate(due_date) < getdate(posting_date):
frappe.throw(_("Due Date cannot be before Posting Date"))
else:
default_due_date = get_due_date(posting_date, party_type, party, company)
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
is_credit_controller = frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
if is_credit_controller:
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
.format(date_diff(due_date, default_due_date)))
else:
frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))

View File

@@ -1,19 +1,19 @@
{
"creation": "2014-08-28 11:11:39.796473",
"disabled": 0,
"doc_type": "Journal Entry",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"idx": 2,
"modified": "2015-01-12 11:02:25.716825",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Credit Note",
"owner": "Administrator",
"parent": "Journal Entry",
"parentfield": "__print_formats",
"parenttype": "DocType",
"print_format_type": "Server",
"creation": "2014-08-28 11:11:39.796473",
"custom_format": 0,
"disabled": 0,
"doc_type": "Journal Entry",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"idx": 2,
"modified": "2015-07-22 17:42:01.560817",
"modified_by": "Administrator",
"name": "Credit Note",
"owner": "Administrator",
"parent": "Journal Entry",
"parentfield": "__print_formats",
"parenttype": "DocType",
"print_format_type": "Server",
"standard": "Yes"
}
}

View File

@@ -0,0 +1,17 @@
{
"creation": "2015-07-22 17:45:22.220567",
"custom_format": 1,
"disabled": 0,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 6in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}<br>\n</p>\n\n<hr>\n\n{%- for label, value in (\n (_(\"Receipt No\"), doc.name),\n (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"</strong><br>\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t<div class=\"row\">\n\t\t <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n\t\t <div class=\"col-xs-8\">{{ value }}</div>\n\t\t</div>\n{%- endfor -%}\n\n<hr>\n<br>\n<p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n</p>",
"modified": "2015-07-22 17:45:22.220567",
"modified_by": "Administrator",
"name": "Credit Note - Negative Invoice",
"owner": "Administrator",
"print_format_builder": 0,
"print_format_type": "Server",
"standard": "Yes"
}

View File

@@ -1,17 +1,17 @@
{
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-04-22 16:16:03",
"docstatus": 0,
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:10.985354",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Payable",
"owner": "Administrator",
"ref_doctype": "Purchase Invoice",
"report_name": "Accounts Payable",
"report_type": "Report Builder"
}
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-04-22 16:16:03",
"docstatus": 0,
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2015-07-24 01:08:20.996267",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Payable",
"owner": "Administrator",
"ref_doctype": "Purchase Invoice",
"report_name": "Accounts Payable",
"report_type": "Script Report"
}

View File

@@ -51,7 +51,7 @@ class ReceivablePayableReport(object):
currency_precision = get_currency_precision() or 2
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
voucher_details = self.get_voucher_details()
voucher_details = self.get_voucher_details(args.get("party_type"))
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
@@ -153,23 +153,26 @@ class ReceivablePayableReport(object):
return self.party_map
def get_voucher_details(self):
def get_voucher_details(self, party_type):
voucher_details = frappe._dict()
if party_type == "Customer":
for si in frappe.db.sql("""select name, due_date
from `tabSales Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(si.name, si)
for si in frappe.db.sql("""select name, due_date
from `tabSales Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(si.name, si)
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(pi.name, pi)
if party_type == "Supplier":
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(pi.name, pi)
return voucher_details
def get_gl_entries(self, party_type):
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions(party_type)
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry`
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, debit, credit,
voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
.format(conditions), values, as_dict=True)
@@ -187,7 +190,7 @@ class ReceivablePayableReport(object):
if self.filters.get(party_type_field):
conditions.append("party=%s")
values.append(self.filters.get(party_type_field))
values.append(self.filters.get(party_type_field))
return " and ".join(conditions), values

View File

@@ -83,7 +83,7 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
calculate_values(accounts, gl_entries_by_account, period_list)
calculate_values(accounts_by_name, gl_entries_by_account, period_list)
accumulate_values_into_parents(accounts, accounts_by_name, period_list)
out = prepare_data(accounts, balance_must_be, period_list)
@@ -92,16 +92,14 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
return out
def calculate_values(accounts, gl_entries_by_account, period_list):
for d in accounts:
for name in ([d.name] + (d.collapsed_children or [])):
for entry in gl_entries_by_account.get(name, []):
for period in period_list:
entry.posting_date = getdate(entry.posting_date)
# check if posting date is within the period
if entry.posting_date <= period.to_date:
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
def calculate_values(accounts_by_name, gl_entries_by_account, period_list):
for entries in gl_entries_by_account.values():
for entry in entries:
d = accounts_by_name.get(entry.account)
for period in period_list:
# check if posting date is within the period
if entry.posting_date <= period.to_date:
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
@@ -159,22 +157,8 @@ def add_total_row(out, balance_must_be, period_list):
out.append({})
def get_accounts(company, root_type):
# root lft, rgt
root_account = frappe.db.sql("""select lft, rgt from `tabAccount`
where company=%s and root_type=%s and ifnull(parent_account, '') = ''
order by lft limit 1""",
(company, root_type), as_dict=True)
if not root_account:
return None
lft, rgt = root_account[0].lft, root_account[0].rgt
accounts = frappe.db.sql("""select * from `tabAccount`
where company=%(company)s and lft >= %(lft)s and rgt <= %(rgt)s order by lft""",
{ "company": company, "lft": lft, "rgt": rgt }, as_dict=True)
return accounts
return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
def filter_accounts(accounts, depth=10):
parent_children_map = {}
@@ -196,14 +180,6 @@ def filter_accounts(accounts, depth=10):
filtered_accounts.append(child)
add_to_list(child.name, level + 1)
else:
# include all children at level lower than the depth
parent_account = accounts_by_name[parent]
parent_account["collapsed_children"] = []
for d in accounts:
if d.lft > parent_account.lft and d.rgt < parent_account.rgt:
parent_account["collapsed_children"].append(d.name)
add_to_list(None, 0)
return filtered_accounts, accounts_by_name
@@ -234,7 +210,7 @@ def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closi
if from_date:
additional_conditions.append("and posting_date >= %(from_date)s")
gl_entries = frappe.db.sql("""select * from `tabGL Entry`
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening from `tabGL Entry`
where company=%(company)s
{additional_conditions}
and posting_date <= %(to_date)s

View File

@@ -1,5 +1,5 @@
<div style="margin-bottom: 7px;" class="text-center">
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
{%= frappe.boot.letter_heads[filters.letter_head || frappe.defaults.get_default("letter_head")] %}
</div>
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
<h4 class="text-center">{%= (filters.party || filters.account) && ((filters.party || filters.account) + ", ") || "" %} {%= filters.company %}</h4>

View File

@@ -53,13 +53,9 @@ frappe.query_reports["General Ledger"] = {
{
"fieldname":"party_type",
"label": __("Party Type"),
"fieldtype": "Link",
"options": "DocType",
"get_query": function() {
return {
filters: {"name": ["in", ["Customer", "Supplier"]]}
}
}
"fieldtype": "Select",
"options": ["", "Customer", "Supplier"],
"default": ""
},
{
"fieldname":"party",
@@ -84,6 +80,13 @@ frappe.query_reports["General Ledger"] = {
"fieldname":"group_by_account",
"label": __("Group by Account"),
"fieldtype": "Check",
},
{
"fieldname":"letter_head",
"label": __("Letter Head"),
"fieldtype": "Link",
"options": "Letter Head",
"default": frappe.defaults.get_default("letter_head"),
}
]
}

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, getdate
from frappe.utils import flt, getdate, cstr
from frappe import _
def execute(filters=None):
@@ -66,7 +66,7 @@ def get_gl_entries(filters):
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
voucher_type, voucher_no, cost_center, remarks, is_opening, against
voucher_type, voucher_no, cost_center, remarks, against, is_opening
from `tabGL Entry`
where company=%(company)s {conditions}
{group_by_condition}
@@ -91,6 +91,9 @@ def get_conditions(filters):
if filters.get("party"):
conditions.append("party=%(party)s")
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
conditions.append("posting_date >=%(from_date)s")
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
@@ -148,14 +151,15 @@ def initialize_gle_map(gl_entries):
def get_accountwise_gle(filters, gl_entries, gle_map):
opening, total_debit, total_credit = 0, 0, 0
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries:
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
if gle.posting_date < getdate(filters.from_date):
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
gle_map[gle.account].opening += amount
if filters.get("account") or filters.get("party"):
opening += amount
elif gle.posting_date <= getdate(filters.to_date):
elif gle.posting_date <= to_date:
gle_map[gle.account].entries.append(gle)
gle_map[gle.account].total_debit += flt(gle.debit, 3)
gle_map[gle.account].total_credit += flt(gle.credit, 3)

View File

@@ -86,23 +86,23 @@ class GrossProfitGenerator(object):
self.filters = frappe._dict(filters)
self.load_invoice_items()
self.load_stock_ledger_entries()
self.load_sales_bom()
self.load_product_bundle()
self.load_non_stock_items()
self.process()
def process(self):
self.grouped = {}
for row in self.si_list:
if self.skip_row(row, self.sales_boms):
if self.skip_row(row, self.product_bundles):
continue
row.base_amount = flt(row.base_net_amount)
sales_boms = self.sales_boms.get(row.parenttype, {}).get(row.parent, frappe._dict())
product_bundles = self.product_bundles.get(row.parenttype, {}).get(row.parent, frappe._dict())
# get buying amount
if row.item_code in sales_boms:
row.buying_amount = self.get_buying_amount_from_sales_bom(row, sales_boms[row.item_code])
if row.item_code in product_bundles:
row.buying_amount = self.get_buying_amount_from_product_bundle(row, product_bundles[row.item_code])
else:
row.buying_amount = self.get_buying_amount(row, row.item_code)
@@ -152,13 +152,13 @@ class GrossProfitGenerator(object):
self.grouped_data.append(new_row)
def skip_row(self, row, sales_boms):
def skip_row(self, row, product_bundles):
if self.filters.get("group_by") != "Invoice" and not row.get(scrub(self.filters.get("group_by"))):
return True
def get_buying_amount_from_sales_bom(self, row, sales_bom):
def get_buying_amount_from_product_bundle(self, row, product_bundle):
buying_amount = 0.0
for bom_item in sales_bom:
for bom_item in product_bundle:
if bom_item.get("parent_detail_docname")==row.item_row:
buying_amount += self.get_buying_amount(row, bom_item.item_code)
@@ -174,17 +174,16 @@ class GrossProfitGenerator(object):
return flt(row.qty) * item_rate
else:
if row.update_stock or row.dn_detail:
my_sle = self.sle.get((item_code, row.warehouse))
if (row.update_stock or row.dn_detail) and my_sle:
parenttype, parent, item_row = row.parenttype, row.parent, row.item_row
if row.dn_detail:
row.parenttype = "Delivery Note"
row.parent = row.delivery_note
row.item_row = row.dn_detail
my_sle = self.sle.get((item_code, row.warehouse))
parenttype, parent, item_row = "Delivery Note", row.delivery_note, row.dn_detail
for i, sle in enumerate(my_sle):
# find the stock valution rate from stock ledger entry
if sle.voucher_type == row.parenttype and row.parent == sle.voucher_no and \
sle.voucher_detail_no == row.item_row:
if sle.voucher_type == parenttype and parent == sle.voucher_no and \
sle.voucher_detail_no == 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)
@@ -247,13 +246,13 @@ class GrossProfitGenerator(object):
self.sle[(r.item_code, r.warehouse)].append(r)
def load_sales_bom(self):
self.sales_boms = {}
def load_product_bundle(self):
self.product_bundles = {}
for d in frappe.db.sql("""select parenttype, parent, parent_item,
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
from `tabPacked Item` where docstatus=1""", as_dict=True):
self.sales_boms.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
self.product_bundles.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
frappe._dict()).setdefault(d.parent_item, []).append(d)
def load_non_stock_items(self):

View File

@@ -3,6 +3,14 @@
frappe.query_reports["Payment Period Based On Invoice Date"] = {
"filters": [
{
fieldname:"company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_user_default("company")
},
{
fieldname: "from_date",
label: __("From Date"),
@@ -23,27 +31,28 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
default: "Incoming"
},
{
fieldname:"account",
label: __("Account"),
fieldtype: "Link",
options: "Account",
get_query: function() {
"fieldname":"party_type",
"label": __("Party Type"),
"fieldtype": "Link",
"options": "DocType",
"get_query": function() {
return {
query: "erpnext.controllers.queries.get_account_list",
filters: {
"report_type": "Balance Sheet",
company: frappe.query_report.filters_by_name.company.get_value()
}
filters: {"name": ["in", ["Customer", "Supplier"]]}
}
}
},
{
fieldname:"company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_user_default("company")
"fieldname":"party",
"label": __("Party"),
"fieldtype": "Dynamic Link",
"get_options": function() {
var party_type = frappe.query_report.filters_by_name.party_type.get_value();
var party = frappe.query_report.filters_by_name.party.get_value();
if(party && !party_type) {
frappe.throw(__("Please select Party Type first"));
}
return party_type;
}
},
]
}

View File

@@ -9,8 +9,9 @@ from frappe.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
validate_filters(filters)
columns = get_columns(filters)
entries = get_entries(filters)
invoice_posting_date_map = get_invoice_posting_date_map(filters)
against_date = ""
@@ -20,67 +21,72 @@ def execute(filters=None):
for d in entries:
if d.against_voucher:
against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or ""
outstanding_amount = flt(d.debit) or -1 * flt(d.credit)
payment_amount = flt(d.debit) or -1 * flt(d.credit)
else:
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
outstanding_amount = flt(d.credit) or -1 * flt(d.debit)
payment_amount = flt(d.credit) or -1 * flt(d.debit)
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
row = [d.name, d.party_type, d.party, d.posting_date, d.against_voucher or d.against_invoice,
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
if d.against_voucher or d.against_invoice:
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, outstanding_amount)
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, payment_amount)
else:
row += ["", "", "", "", ""]
data.append(row)
return columns, data
def validate_filters(filters):
if (filters.get("payment_type") == "Incoming" and filters.get("party_type") == "Supplier") or \
(filters.get("payment_type") == "Outgoing" and filters.get("party_type") == "Customer"):
frappe.throw(_("{0} payment entries can not be filtered by {1}")\
.format(filters.payment_type, filters.party_type))
def get_columns():
return [_("Journal Entry") + ":Link/Journal Entry:140", _("Account") + ":Link/Account:140",
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
def get_columns(filters):
return [_("Journal Entry") + ":Link/Journal Entry:140",
_("Party Type") + ":Link/DocType:100", _("Party") + ":Dynamic Link/Party Type:140",
_("Posting Date") + ":Date:100",
_("Against Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == "Outgoing" else ":Link/Sales Invoice:130"),
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100"
]
def get_conditions(filters):
conditions = ""
party = None
conditions = []
if filters.get("account"):
party = filters["account"]
else:
conditions += " and company = '%s'" % frappe.db.escape(filters["company"])
if not filters.get("party_type"):
if filters.get("payment_type") == "Outgoing":
filters["party_type"] = "Supplier"
else:
filters["party_type"] = "Customer"
if filters.get("party_type"):
conditions.append("jvd.party_type=%(party_type)s")
account_type = "Receivable" if filters.get("payment_type") == "Incoming" else "Payable"
if filters.get("party"):
conditions.append("jvd.party=%(party)s")
conditions += """ and account in
(select name from tabAccount
where account_type = '{0}'
and company='{1}')""".format(account_type, frappe.db.escape(filters["company"]))
if party:
conditions += " and jvd.party = '%s'" % frappe.db.escape(party)
else:
conditions += " and ifnull(jvd.party, '') != ''"
if filters.get("company"):
conditions.append("jv.company=%(company)s")
if filters.get("from_date"):
conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
conditions.append("jv.posting_date >= %(from_date)s")
if filters.get("to_date"):
conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
conditions.append("jv.posting_date <= %(to_date)s")
return conditions
return "and {}".format(" and ".join(conditions)) if conditions else ""
def get_entries(filters):
conditions = get_conditions(filters)
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
entries = frappe.db.sql("""select jv.name, jvd.party_type, jvd.party, jv.posting_date,
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
jv.cheque_no, jv.cheque_date, jv.remark
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
conditions, as_dict=1, debug=1)
conditions, filters, as_dict=1)
return entries

View File

@@ -4,12 +4,12 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, flt, getdate, formatdate
from frappe.utils import cint, flt, getdate, formatdate, cstr
from erpnext.accounts.report.financial_statements import filter_accounts, get_gl_entries
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
def execute(filters):
def execute(filters=None):
validate_filters(filters)
data = get_data(filters)
columns = get_columns()
@@ -45,8 +45,8 @@ def validate_filters(filters):
filters.to_date = filters.year_end_date
def get_data(filters):
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""",
filters.company, as_dict=True)
accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
if not accounts:
return None
@@ -56,17 +56,58 @@ def get_data(filters):
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
where company=%s""", (filters.company,))[0]
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt,
gl_entries_by_account = get_gl_entries(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt,
ignore_closing_entries=not flt(filters.with_period_closing_entry))
total_row = calculate_values(accounts, gl_entries_by_account, filters)
opening_balances = get_opening_balances(filters)
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row)
return data
def get_opening_balances(filters):
balance_sheet_opening = get_rootwise_opening_balances(filters, "Balance Sheet")
pl_opening = get_rootwise_opening_balances(filters, "Profit and Loss")
balance_sheet_opening.update(pl_opening)
return balance_sheet_opening
def get_rootwise_opening_balances(filters, report_type):
additional_conditions = " and posting_date >= %(year_start_date)s" \
if report_type == "Profit and Loss" else ""
if not flt(filters.with_period_closing_entry):
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
gle = frappe.db.sql("""
select
account, sum(ifnull(debit, 0)) as opening_debit, sum(ifnull(credit, 0)) as opening_credit
from `tabGL Entry`
where
company=%(company)s
{additional_conditions}
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
and account in (select name from `tabAccount` where report_type=%(report_type)s)
group by account""".format(additional_conditions=additional_conditions),
{
"company": filters.company,
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date
},
as_dict=True)
opening = frappe._dict()
for d in gle:
opening.setdefault(d.account, d)
return opening
def calculate_values(accounts, gl_entries_by_account, filters):
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
init = {
"opening_debit": 0.0,
"opening_credit": 0.0,
@@ -87,30 +128,18 @@ def calculate_values(accounts, gl_entries_by_account, filters):
for d in accounts:
d.update(init.copy())
# add opening
d["opening_debit"] = opening_balances.get(d.name, {}).get("opening_debit", 0)
d["opening_credit"] = opening_balances.get(d.name, {}).get("opening_credit", 0)
for entry in gl_entries_by_account.get(d.name, []):
posting_date = getdate(entry.posting_date)
# opening
if posting_date < filters.from_date:
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
(filters.year_start_date <= posting_date < filters.from_date))
if is_valid_opening:
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
elif posting_date <= filters.to_date:
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
else:
d["debit"] += flt(entry.debit)
d["credit"] += flt(entry.credit)
if cstr(entry.is_opening) != "Yes":
d["debit"] += flt(entry.debit)
d["credit"] += flt(entry.credit)
total_row["debit"] += d["debit"]
total_row["credit"] += d["credit"]
return total_row

View File

@@ -91,7 +91,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
# different filter for group and ledger - improved performance
if acc.is_group:
cond.append("""exists (
select * from `tabAccount` ac where ac.name = gle.account
select name from `tabAccount` ac where ac.name = gle.account
and ac.lft >= %s and ac.rgt <= %s
)""" % (acc.lft, acc.rgt))
else:
@@ -397,7 +397,7 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
for d in outstanding_voucher_list:
payment_amount = frappe.db.sql("""
select ifnull(sum(ifnull({amount_query}, 0)), 0)
select ifnull(sum({amount_query}), 0)
from
`tabGL Entry`
where

View File

@@ -70,10 +70,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
erpnext.utils.get_address_display(this.frm);
},
contact_person: function() {
erpnext.utils.get_contact_details(this.frm);
},
buying_price_list: function() {
this.apply_price_list();
},
@@ -168,8 +164,10 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount"]);
this.frm.doc.total_amount_to_pay = flt(this.frm.doc.base_grand_total - this.frm.doc.write_off_amount,
precision("total_amount_to_pay"));
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
precision("outstanding_amount"));
if (!this.frm.doc.is_return) {
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
precision("outstanding_amount"));
}
}
}
});

View File

@@ -41,8 +41,7 @@ class PurchaseCommon(BuyingController):
def validate_for_items(self, obj):
items = []
for d in obj.get("items"):
# validation for valid qty
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
if not d.qty:
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
# udpate with latest quantities

View File

@@ -11,39 +11,32 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
this._super();
// this.frm.dashboard.reset();
if(doc.docstatus == 1 && doc.status != 'Stopped'){
// cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
// doc.per_received);
// cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
// doc.per_billed);
if(doc.docstatus == 1 && doc.status != 'Stopped') {
if(flt(doc.per_received, 2) < 100) {
cur_frm.add_custom_button(__('Make Purchase Receipt'),
this.make_purchase_receipt);
cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);
if(doc.is_subcontracted==="Yes") {
cur_frm.add_custom_button(__('Transfer Material to Supplier'),
function() { me.make_stock_entry() });
cur_frm.add_custom_button(__('Transfer Material to Supplier'), this.make_stock_entry);
}
}
if(flt(doc.per_billed, 2) < 100)
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice,
frappe.boot.doctype_icons["Purchase Invoice"]);
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice);
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'],
"icon-exclamation", "btn-default");
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);
} else if(doc.docstatus===0) {
cur_frm.cscript.add_from_mappers();
}
if(doc.docstatus == 1 && doc.status == 'Stopped')
cur_frm.add_custom_button(__('Unstop Purchase Order'),
cur_frm.cscript['Unstop Purchase Order'], "icon-check");
cur_frm.add_custom_button(__('Unstop Purchase Order'), cur_frm.cscript['Unstop Purchase Order']);
},
make_stock_entry: function() {
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }),
me = this;
var me = this;
if(items.length===1) {
me._make_stock_entry(items[0]);
return;
@@ -96,7 +89,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default"
}
);
cur_frm.add_custom_button(__('From Supplier Quotation'),
@@ -110,7 +103,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default"
}
);
cur_frm.add_custom_button(__('For Supplier'),
@@ -122,7 +115,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
docstatus: ["!=", 2],
}
})
}, "icon-download", "btn-default"
}
);
},
@@ -249,7 +242,7 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "schedule_date");
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
}
frappe.provide("erpnext.buying");

View File

@@ -53,7 +53,7 @@
"fieldtype": "Data",
"hidden": 0,
"in_list_view": 0,
"label": "Name",
"label": "Supplier Name",
"permlevel": 0,
"read_only": 1
},
@@ -457,7 +457,7 @@
{
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount (Company Currency)",
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
@@ -868,12 +868,21 @@
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"depends_on": "eval:doc.is_recurring==1",
"fieldname": "recurring_print_format",
"fieldtype": "Link",
"label": "Recurring Print Format",
"options": "Print Format",
"permlevel": 0,
"precision": ""
}
],
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2015-06-02 17:15:44.711032",
"modified": "2015-07-13 05:28:29.397705",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
@@ -890,7 +899,7 @@
"print": 0,
"read": 1,
"report": 1,
"role": "Material User",
"role": "Stock User",
"submit": 0,
"write": 0
},

View File

@@ -1,247 +1,247 @@
{
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:11",
"description": "Supplier of Goods or Services.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:11",
"description": "Supplier of Goods or Services.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"fieldname": "basic_info",
"fieldtype": "Section Break",
"label": "",
"oldfieldtype": "Section Break",
"options": "icon-user",
"fieldname": "basic_info",
"fieldtype": "Section Break",
"label": "",
"oldfieldtype": "Section Break",
"options": "icon-user",
"permlevel": 0
},
},
{
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"no_copy": 1,
"oldfieldname": "naming_series",
"oldfieldtype": "Select",
"options": "SUPP-",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"no_copy": 1,
"oldfieldname": "naming_series",
"oldfieldtype": "Select",
"options": "SUPP-",
"permlevel": 0
},
},
{
"fieldname": "supplier_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Supplier Name",
"no_copy": 1,
"oldfieldname": "supplier_name",
"oldfieldtype": "Data",
"permlevel": 0,
"fieldname": "supplier_name",
"fieldtype": "Data",
"in_list_view": 0,
"label": "Supplier Name",
"no_copy": 1,
"oldfieldname": "supplier_name",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "column_break0",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break0",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
},
{
"fieldname": "supplier_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Supplier Type",
"oldfieldname": "supplier_type",
"oldfieldtype": "Link",
"options": "Supplier Type",
"permlevel": 0,
"fieldname": "supplier_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Supplier Type",
"oldfieldname": "supplier_type",
"oldfieldtype": "Link",
"options": "Supplier Type",
"permlevel": 0,
"reqd": 1
},
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"label": "Address & Contacts",
"oldfieldtype": "Column Break",
"options": "icon-map-marker",
"depends_on": "eval:!doc.__islocal",
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"label": "Address & Contacts",
"oldfieldtype": "Column Break",
"options": "icon-map-marker",
"permlevel": 0
},
},
{
"fieldname": "address_html",
"fieldtype": "HTML",
"label": "Address HTML",
"permlevel": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
"label": "Address HTML",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
},
{
"fieldname": "contact_html",
"fieldtype": "HTML",
"label": "Contact HTML",
"permlevel": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
"label": "Contact HTML",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "default_payable_accounts",
"fieldtype": "Section Break",
"label": "Default Payable Accounts",
"fieldname": "default_payable_accounts",
"fieldtype": "Section Break",
"label": "Default Payable Accounts",
"permlevel": 0
},
},
{
"depends_on": "eval:!doc.__islocal",
"description": "Mention if non-standard receivable account applicable",
"fieldname": "accounts",
"fieldtype": "Table",
"label": "Accounts",
"options": "Party Account",
"depends_on": "eval:!doc.__islocal",
"description": "Mention if non-standard receivable account applicable",
"fieldname": "accounts",
"fieldtype": "Table",
"label": "Accounts",
"options": "Party Account",
"permlevel": 0
},
},
{
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"permlevel": 0
},
},
{
"fieldname": "default_currency",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Default Currency",
"no_copy": 1,
"options": "Currency",
"fieldname": "default_currency",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Default Currency",
"no_copy": 1,
"options": "Currency",
"permlevel": 0
},
},
{
"fieldname": "default_price_list",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Price List",
"options": "Price List",
"fieldname": "default_price_list",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Price List",
"options": "Price List",
"permlevel": 0
},
},
{
"fieldname": "default_taxes_and_charges",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Taxes and Charges",
"options": "Purchase Taxes and Charges Template",
"fieldname": "default_taxes_and_charges",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Taxes and Charges",
"options": "Purchase Taxes and Charges Template",
"permlevel": 0
},
},
{
"fieldname": "credit_days",
"fieldtype": "Int",
"label": "Credit Days",
"fieldname": "credit_days",
"fieldtype": "Int",
"label": "Credit Days",
"permlevel": 0
},
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "column_break2",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
},
{
"fieldname": "website",
"fieldtype": "Data",
"label": "Website",
"oldfieldname": "website",
"oldfieldtype": "Data",
"fieldname": "website",
"fieldtype": "Data",
"label": "Website",
"oldfieldname": "website",
"oldfieldtype": "Data",
"permlevel": 0
},
},
{
"description": "Statutory info and other general information about your Supplier",
"fieldname": "supplier_details",
"fieldtype": "Text",
"label": "Supplier Details",
"oldfieldname": "supplier_details",
"oldfieldtype": "Code",
"description": "Statutory info and other general information about your Supplier",
"fieldname": "supplier_details",
"fieldtype": "Text",
"label": "Supplier Details",
"oldfieldname": "supplier_details",
"oldfieldtype": "Code",
"permlevel": 0
},
},
{
"fieldname": "communications",
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
"options": "Communication",
"permlevel": 0,
"fieldname": "communications",
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
"options": "Communication",
"permlevel": 0,
"print_hide": 1
}
],
"icon": "icon-user",
"idx": 1,
"modified": "2015-02-24 17:35:03.821319",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
"owner": "Administrator",
],
"icon": "icon-user",
"idx": 1,
"modified": "2015-07-13 05:28:29.121285",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
"owner": "Administrator",
"permissions": [
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User"
},
},
{
"amend": 0,
"create": 0,
"delete": 0,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase Manager",
"submit": 0,
"amend": 0,
"create": 0,
"delete": 0,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase Manager",
"submit": 0,
"write": 0
},
},
{
"amend": 0,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase Master Manager",
"share": 1,
"submit": 0,
"amend": 0,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase Master Manager",
"share": 1,
"submit": 0,
"write": 1
},
},
{
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Material User"
},
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Stock User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Material Manager"
},
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock Manager"
},
{
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Accounts User"
},
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager"
}
],
"search_fields": "supplier_name, supplier_type",
],
"search_fields": "supplier_name, supplier_type",
"title_field": "supplier_name"
}
}

View File

@@ -439,7 +439,7 @@
{
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount (Company Currency)",
"label": "Additional Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
@@ -660,7 +660,7 @@
"icon": "icon-shopping-cart",
"idx": 1,
"is_submittable": 1,
"modified": "2015-06-02 17:15:57.283516",
"modified": "2015-07-13 05:28:30.252636",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",
@@ -723,7 +723,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "Material User",
"role": "Stock User",
"submit": 0,
"write": 0
},

View File

@@ -0,0 +1,3 @@
Leave change log files in this folder for user release notes.
(this file is just a place holder, don't delete it)

View File

@@ -0,0 +1,17 @@
- Performance upgrade in Trial Balance, General Ledger, AR/AP, Balance Sheet and P&L Statement reports
- Add index on Account and GL Entry, Sales Invoice and Purchase Invoice table
- Don't create Time Logs against Production Order if Workstation is not specified in Operations
- Task should be mandatory in Time Log only when Project is mentioned but Production Order is not
- Supplier invoice no unique validation and supplier invoice date can not be after posting date
- Removed BOM No from mandatory from Stock Entry against Production Order
- Load tasks in project for printing purpose
- Added Customers Not Buying Since Long Time against Sales Invoice
- POS - search by Item Group
- Payment period based on invoice date: show party columns and filter based on party
- Barcode added to Purchase Receipt
- Fetch item name and desc on change of item code in Quality Inspection
- Show item name in item grid view based 'In List View' property
- Validate and update manufactured qty in Stock Entry
- Show only users with Expense Approver role in Expense Claim Approver field
- Over Production Allowance Percentage Setting added to Manufacturing Settings
- Activity Cost - Mandatory removed for Employee

View File

@@ -0,0 +1 @@
- Open notification of Sales Order and Purchase Order based on whether Invoice is created against them. For eg. If a Sales Order is not Invoiced, it will be considered as open. Previously it was considered open if Delivery Note was created against Sales Order.

View File

@@ -0,0 +1,8 @@
- Item variants is now manageable via dedicated tool **Manage Variants**. To learn about it, check [Manual Page for Item variants](https://manual.erpnext.com/contents/stock/item/item-variants)
- Against account in General Ledger will show Party instead of Account (which is not useful)
- Print format for recurring documents can be set by the users
- Recurring documents won't be created for Stopped Sales / Purchase Orders.
- Lead status will be changed to 'Opportunity' when Lead converted to Opportunity
- Amount in Journal Entry list view
- Currency exchange rate is now automatically fetched from fixer.io, instead of jsonrates.com
- Item image is now available in Sales / Purchase Invoice

View File

@@ -0,0 +1,3 @@
- Hide zero balance rows in batch-wise balance history report
- Autocomplete issue fixed in Manage Variants
- Remove user permission (Employee role) if user id is unset from Employee record

View File

@@ -0,0 +1,4 @@
- Mode of Payment added to POS Profile
- Expired Batch is not allowed in stock entry of type manufacturing / repack
- Validate item rate against reference document with tolerance 0.009
- Set Customer name in opportunity as per company name in lead

View File

@@ -0,0 +1,8 @@
- Customer's credit days based on fixed days / last day of the next month **[Sponsored by McLean Images](http://www.mcleans.net.au)**
- Production Order is not allowed against Item Template (for Variants)
- Currency symbol fixed for outstanding amount and advance amount field in Sales Invoice
- A Contact can be linked to Customer, Supplier and Sales partner at the same time
- Validation added to prevent task being closed with open dependent tasks
- Blocked stock transactions against an expired batch
- Added Employees in Newsletter List
- Link Address to Customer / Supplier / Lead, based on logged-in user, if created in portal

View File

@@ -0,0 +1,9 @@
- New help videos for Selling, Buying, Human Resource, Manufacturing and Buying
- Role rename: **Material User** is now **Stock User**
- Role rename: **Material Manager** is now **Stock Manager**
- Role rename: **Material Master Manager** is now **Item Manager**
- Fixed inconsistent visibility of 'Add to Cart' button
- Use Customer's Price List in Shopping Cart
- Fixed Address creation from Shopping Cart
- Display images in website's Item and Item List pages when the filename has paranthesis in its name

View File

@@ -0,0 +1,11 @@
- **Sales Return**: Create Delivery Note or Sales Invoice ('Updated Stock' option checked) with negative quantity.
- **Purchase Return**: Create Purchase Receipt with negative quantity
- **Credit / Debit Note**: Create Sales / Purchase Invoice with negative qtuantity against original invoice.
- Outgoing rate in Purchase Return based on reference / original Purchase Receipt rate
- Global switch added to disable capacity planning in manufacturing settings
- Opening Balance row added to Stock Ledger Report
- SMS delivery message and log
- Added users, employees, sample data via Setup Wizard
- Letter Head option in General Ledger report
- Fetch Template Bom if no BOM is set against Item Variant in Production Order
- Fetch items from Packing List while raising Material Request against SO

View File

@@ -73,6 +73,11 @@ def get_data():
"label": _("Setup"),
"icon": "icon-cog",
"items": [
{
"type": "doctype",
"name": "Company",
"description": _("Company (not Customer or Supplier) master.")
},
{
"type": "doctype",
"name": "Fiscal Year",

View File

@@ -42,6 +42,11 @@ def get_data():
"name": "SMS Center",
"description":_("Send mass SMS to your contacts"),
},
{
"type": "doctype",
"name": "SMS Log",
"description":_("Logs for maintaining sms delivery status"),
}
]
},
{

View File

@@ -64,7 +64,7 @@ def get_data():
"type": "module"
},
"Learn": {
"color": "#7272FF",
"color": "#FCB868",
"force_show": True,
"icon": "icon-facetime-video",
"type": "module",

View File

@@ -60,7 +60,7 @@ def get_data():
"items": [
{
"type": "doctype",
"name": "Salary Manager",
"name": "Process Payroll",
"label": _("Process Payroll"),
"description":_("Generate Salary Slips"),
"hide_count": True

View File

@@ -15,8 +15,12 @@ def get_data():
"type": "help",
"label": _("Setup Wizard"),
"youtube_id": "oIOf_zCFWKQ"
}
},
{
"type": "help",
"label": _("Customizing Forms"),
"youtube_id": "pJhL9mmxV_U"
},
]
},
@@ -93,6 +97,16 @@ def get_data():
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Sales Order to Payment"),
"youtube_id": "7AMq4lqkN4A"
},
{
"type": "help",
"label": _("Point-of-Sale"),
"youtube_id": "4WkelWkbP_c"
}
]
},
{
@@ -108,11 +122,6 @@ def get_data():
"label": _("Opening Stock Balance"),
"youtube_id": "0yPgrtfeCTs"
},
{
"type": "help",
"label": _("Item Variants"),
"youtube_id": "OGBETlCzU5o"
},
]
},
{
@@ -123,6 +132,12 @@ def get_data():
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Material Request to Purchase Order"),
"youtube_id": "4TN9kPyfIqM"
},
]
},
{
@@ -133,6 +148,47 @@ def get_data():
"label": _("Bill of Materials"),
"youtube_id": "hDV0c1OeWLo"
},
{
"type": "help",
"label": _("Production Planning Tool"),
"youtube_id": "CzatSl4zJ2Y"
},
{
"type": "help",
"label": _("Production Order"),
"youtube_id": "ZotgLyp2YFY"
},
]
}
},
{
"label": _("Human Resource"),
"items": [
{
"type": "help",
"label": _("Setting up Employees"),
"youtube_id": "USfIUdZlUhw"
},
{
"type": "help",
"label": _("Leave Management"),
"youtube_id": "fc0p_AXebc8"
},
{
"type": "help",
"label": _("Expense Claims"),
"youtube_id": "5SZHJF--ZFY"
},
]
},
{
"label": _("Projects"),
"items": [
{
"type": "help",
"label": _("Managing Projects"),
"youtube_id": "egxIGwtoKI4"
},
]
},
]

View File

@@ -103,6 +103,12 @@ def get_data():
"name": "Completed Production Orders",
"doctype": "Production Order"
},
{
"type": "report",
"is_query_report": True,
"name": "BOM Search",
"doctype": "BOM"
},
]
},
{

View File

@@ -48,6 +48,11 @@ def get_data():
"name": "SMS Center",
"description":_("Send mass SMS to your contacts"),
},
{
"type": "doctype",
"name": "SMS Log",
"description":_("Logs for maintaining sms delivery status"),
},
{
"type": "doctype",
"name": "Newsletter",
@@ -144,7 +149,7 @@ def get_data():
},
{
"type": "doctype",
"name": "Sales BOM",
"name": "Product Bundle",
"description": _("Bundle items at time of sale."),
},
{
@@ -237,6 +242,12 @@ def get_data():
"route": "query-report/Sales Person Target Variance Item Group-Wise",
"doctype": "Sales Person",
},
{
"type": "report",
"is_query_report": True,
"name": "BOM Search",
"doctype": "BOM"
},
{
"type": "report",
"is_query_report": True,

View File

@@ -110,43 +110,7 @@ def get_data():
"description": _("Setup SMS gateway settings")
},
]
},
{
"label": _("Masters"),
"icon": "icon-star",
"items": [
{
"type": "doctype",
"name": "Company",
"description": _("Company (not Customer or Supplier) master.")
},
{
"type": "doctype",
"name": "Item",
"description": _("Item master.")
},
{
"type": "doctype",
"name": "Customer",
"description": _("Customer master.")
},
{
"type": "doctype",
"name": "Supplier",
"description": _("Supplier master.")
},
{
"type": "doctype",
"name": "Contact",
"description": _("Contact master.")
},
{
"type": "doctype",
"name": "Address",
"description": _("Address master.")
},
]
},
}
]
for module, label, icon in (

View File

@@ -83,6 +83,11 @@ def get_data():
"name": "Stock UOM Replace Utility",
"description": _("Change UOM for an Item."),
},
{
"type": "doctype",
"name": "Manage Variants",
"description": _("Manage Item Variants."),
},
]
},
{

View File

@@ -1,92 +0,0 @@
{
"allow_rename": 1,
"autoname": "field:party_type_name",
"creation": "2014-04-07 12:32:18.010384",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"fieldname": "party_type_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Party Type Name",
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "parent_party_type",
"fieldtype": "Link",
"label": "Parent Party Type",
"options": "Party Type",
"permlevel": 0
},
{
"default": "Yes",
"fieldname": "allow_children",
"fieldtype": "Select",
"label": "Allow Children",
"options": "Yes\nNo",
"permlevel": 0
},
{
"fieldname": "default_price_list",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Default Price List",
"options": "Price List",
"permlevel": 0
},
{
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"label": "LFT",
"permlevel": 0,
"read_only": 1,
"search_index": 1
},
{
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"label": "RGT",
"permlevel": 0,
"read_only": 1,
"search_index": 1
},
{
"fieldname": "old_parent",
"fieldtype": "Data",
"hidden": 1,
"label": "Old Parent",
"permlevel": 0,
"read_only": 1
}
],
"modified": "2015-02-05 05:11:42.046004",
"modified_by": "Administrator",
"module": "Contacts",
"name": "Party Type",
"owner": "Administrator",
"permissions": [
{
"apply_user_permissions": 1,
"create": 1,
"permlevel": 0,
"read": 1,
"role": "Sales User",
"share": 1,
"write": 1
},
{
"apply_user_permissions": 1,
"create": 1,
"permlevel": 0,
"read": 1,
"role": "Purchase User",
"share": 1,
"write": 1
}
]
}

View File

@@ -9,6 +9,7 @@ from erpnext.setup.utils import get_company_currency, get_exchange_rate
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
from erpnext.controllers.sales_and_purchase_return import validate_return
class AccountsController(TransactionBase):
def validate(self):
@@ -17,10 +18,14 @@ class AccountsController(TransactionBase):
self.validate_date_with_fiscal_year()
if self.meta.get_field("currency"):
self.calculate_taxes_and_totals()
self.validate_value("base_grand_total", ">=", 0)
if not self.meta.get_field("is_return") or not self.is_return:
self.validate_value("base_grand_total", ">=", 0)
validate_return(self)
self.set_total_in_words()
self.validate_due_date()
if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
self.validate_due_date()
if self.meta.get_field("is_recurring"):
validate_recurring_document(self)
@@ -74,6 +79,9 @@ class AccountsController(TransactionBase):
def validate_due_date(self):
from erpnext.accounts.party import validate_due_date
if self.doctype == "Sales Invoice":
if not self.due_date:
frappe.throw(_("Due Date is mandatory"))
validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
elif self.doctype == "Purchase Invoice":
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)

View File

@@ -26,8 +26,7 @@ class BuyingController(StockController):
def validate(self):
super(BuyingController, self).validate()
if getattr(self, "supplier", None) and not self.supplier_name:
self.supplier_name = frappe.db.get_value("Supplier",
self.supplier, "supplier_name")
self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name")
self.is_item_table_empty()
self.set_qty_as_per_stock_uom()
self.validate_stock_or_nonstock_items()

View File

@@ -194,7 +194,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
and tabBOM.is_active=1
and tabBOM.%(key)s like "%(txt)s"
%(fcond)s %(mcond)s
limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % txt,
limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % frappe.db.escape(txt),
'fcond': get_filters_cond(doctype, filters, conditions),
'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
@@ -207,7 +207,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
where `tabProject`.status not in ("Completed", "Cancelled")
and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s
order by `tabProject`.name asc
limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % txt,
limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % frappe.db.escape(txt),
'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len})
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters):
@@ -229,9 +229,10 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
}, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) })
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("posting_date"):
filters["posting_date"] = nowdate()
cond = ""
if filters.get("posting_date"):
cond = "and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)"
batch_nos = None
args = {
'item_code': filters.get("item_code"),
@@ -251,23 +252,23 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
and sle.warehouse = %(warehouse)s
and sle.batch_no like %(txt)s
and batch.docstatus < 2
and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)
{0}
{match_conditions}
group by batch_no having sum(sle.actual_qty) > 0
order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
if batch_nos:
return batch_nos
else:
return frappe.db.sql("""select name, expiry_date from `tabBatch`
return frappe.db.sql("""select name, expiry_date from `tabBatch` batch
where item = %(item_code)s
and name like %(txt)s
and docstatus < 2
and (ifnull(expiry_date, '')='' or expiry_date >= %(posting_date)s)
{0}
{match_conditions}
order by expiry_date, name desc
limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args, debug=1)
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = []

View File

@@ -33,11 +33,13 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
next_date = next_date or nowdate()
date_field = date_field_map[doctype]
condition = " and ifnull(status, '') != 'Stopped'" if doctype in ("Sales Order", "Purchase Order") else ""
recurring_documents = frappe.db.sql("""select name, recurring_id
from `tab{}` where ifnull(is_recurring, 0)=1
and docstatus=1 and next_date='{}'
and next_date <= ifnull(end_date, '2199-12-31')""".format(doctype, next_date))
from `tab{0}` where ifnull(is_recurring, 0)=1
and docstatus=1 and next_date=%s
and next_date <= ifnull(end_date, '2199-12-31') {1}""".format(doctype, condition), next_date)
exception_list = []
for ref_document, recurring_id in recurring_documents:
@@ -124,7 +126,7 @@ def send_notification(new_rv):
frappe.sendmail(new_rv.notification_email_address,
subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name)])
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=new_rv.recurring_print_format)])
def notify_errors(doc, doctype, party, owner):
from frappe.utils.user import get_system_managers

View File

@@ -0,0 +1,138 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, get_datetime, format_datetime
class StockOverReturnError(frappe.ValidationError): pass
def validate_return(doc):
if not doc.meta.get_field("is_return") or not doc.is_return:
return
validate_return_against(doc)
validate_returned_items(doc)
def validate_return_against(doc):
if not doc.return_against:
frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against")))
else:
filters = {"doctype": doc.doctype, "docstatus": 1, "company": doc.company}
if doc.meta.get_field("customer"):
filters["customer"] = doc.customer
elif doc.meta.get_field("supplier"):
filters["supplier"] = doc.supplier
if not frappe.db.exists(filters):
frappe.throw(_("Invalid {0}: {1}")
.format(doc.meta.get_label("return_against"), doc.return_against))
else:
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
# validate posting date time
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
# validate same exchange rate
if doc.conversion_rate != ref_doc.conversion_rate:
frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
.format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
# validate update stock
if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
.format(doc.return_against))
def validate_returned_items(doc):
valid_items = frappe._dict()
for d in frappe.db.sql("""select item_code, sum(qty) as qty, rate from `tab{0} Item`
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
valid_items.setdefault(d.item_code, d)
if doc.doctype in ("Delivery Note", "Sales Invoice"):
for d in frappe.db.sql("""select item_code, sum(qty) as qty from `tabPacked Item`
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
valid_items.setdefault(d.item_code, d)
already_returned_items = get_already_returned_items(doc)
items_returned = False
for d in doc.get("items"):
if flt(d.qty) < 0:
if d.item_code not in valid_items:
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
.format(d.idx, d.item_code, doc.doctype, doc.return_against))
else:
ref = valid_items.get(d.item_code, frappe._dict())
already_returned_qty = flt(already_returned_items.get(d.item_code))
max_return_qty = flt(ref.qty) - already_returned_qty
if already_returned_qty >= ref.qty:
frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
elif abs(d.qty) > max_return_qty:
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
elif ref.rate and flt(d.rate) != ref.rate:
frappe.throw(_("Row # {0}: Rate must be same as {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
items_returned = True
if not items_returned:
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
def get_already_returned_items(doc):
return frappe._dict(frappe.db.sql("""
select
child.item_code, sum(abs(child.qty)) as qty
from
`tab{0} Item` child, `tab{1}` par
where
child.parent = par.name and par.docstatus = 1
and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
group by item_code
""".format(doc.doctype, doc.doctype), doc.return_against))
def make_return_doc(doctype, source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
def set_missing_values(source, target):
doc = frappe.get_doc(target)
doc.is_return = 1
doc.return_against = source.name
doc.ignore_pricing_rule = 1
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
target_doc.qty = -1* source_doc.qty
if doctype == "Purchase Receipt":
target_doc.received_qty = -1* source_doc.qty
elif doctype == "Purchase Invoice":
target_doc.purchase_receipt = source_doc.purchase_receipt
target_doc.pr_detail = source_doc.pr_detail
doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": doctype,
"validation": {
"docstatus": ["=", 1],
}
},
doctype +" Item": {
"doctype": doctype + " Item",
"fields": {
"purchase_order": "purchase_order",
"purchase_receipt": "purchase_receipt"
},
"postprocess": update_item
},
}, target_doc, set_missing_values)
return doclist

View File

@@ -110,15 +110,14 @@ class SellingController(StockController):
from frappe.utils import money_in_words
company_currency = get_company_currency(self.company)
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None,
"disable_rounded_total"))
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
if self.meta.get_field("base_in_words"):
self.base_in_words = money_in_words(disable_rounded_total and
self.base_grand_total or self.base_rounded_total, company_currency)
abs(self.base_grand_total) or abs(self.base_rounded_total), company_currency)
if self.meta.get_field("in_words"):
self.in_words = money_in_words(disable_rounded_total and
self.grand_total or self.rounded_total, self.currency)
abs(self.grand_total) or abs(self.rounded_total), self.currency)
def calculate_commission(self):
if self.meta.get_field("commission_rate"):
@@ -171,14 +170,11 @@ class SellingController(StockController):
frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx))
if self.doctype == "Sales Order":
if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or
self.has_sales_bom(d.item_code)) and not d.warehouse:
frappe.throw(_("Reserved Warehouse required for stock Item {0} in row {1}").format(d.item_code, d.idx))
reserved_warehouse = d.warehouse
if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
elif self.doctype == "Delivery Note" and d.against_sales_order:
elif self.doctype == "Delivery Note" and d.against_sales_order and not self.is_return:
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
# But in this case reserved qty should only be reduced by 10 and not 12
@@ -191,7 +187,7 @@ class SellingController(StockController):
else:
reserved_qty_for_main_item = -flt(d.qty)
if self.has_sales_bom(d.item_code):
if self.has_product_bundle(d.item_code):
for p in self.get("packed_items"):
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
# the packing details table's qty is already multiplied with parent's qty
@@ -214,15 +210,15 @@ class SellingController(StockController):
'qty': d.qty,
'reserved_qty': reserved_qty_for_main_item,
'uom': d.stock_uom,
'stock_uom': d.stock_uom,
'stock_uom': d.stock_uom,
'batch_no': cstr(d.get("batch_no")).strip(),
'serial_no': cstr(d.get("serial_no")).strip(),
'name': d.name
}))
return il
def has_sales_bom(self, item_code):
return frappe.db.sql("""select name from `tabSales BOM`
def has_product_bundle(self, item_code):
return frappe.db.sql("""select name from `tabProduct Bundle`
where new_item_code=%s and docstatus != 2""", item_code)
def get_already_delivered_qty(self, dn, so, so_detail):

View File

@@ -216,6 +216,17 @@ class StockController(AccountsController):
tuple(item_codes))
return serialized_items
def get_incoming_rate_for_sales_return(self, item_code, against_document):
incoming_rate = 0.0
if against_document and item_code:
incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
from `tabStock Ledger Entry`
where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""",
(self.doctype, against_document, item_code))
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
return incoming_rate
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None):

View File

@@ -77,6 +77,9 @@ class calculate_taxes_and_totals(object):
if not self.discount_amount_applied:
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, self.doc)
if self.doc.meta.get_field("is_return") and self.doc.is_return and tax.charge_type == "Actual":
tax.tax_amount = -1 * tax.tax_amount
tax.item_wise_tax_detail = {}
tax_fields = ["total", "tax_amount_after_discount_amount",
@@ -396,13 +399,15 @@ class calculate_taxes_and_totals(object):
# total_advance is only for non POS Invoice
if self.doc.doctype == "Sales Invoice":
self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
self.doc.precision("outstanding_amount"))
if not self.doc.is_return:
self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
self.doc.precision("outstanding_amount"))
else:
self.doc.round_floats_in(self.doc, ["total_advance", "write_off_amount"])
self.doc.total_amount_to_pay = flt(self.doc.base_grand_total - self.doc.write_off_amount,
self.doc.precision("total_amount_to_pay"))
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
self.doc.precision("outstanding_amount"))
if not self.doc.is_return:
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
self.doc.precision("outstanding_amount"))

View File

@@ -29,7 +29,7 @@
"fieldtype": "Data",
"in_filter": 1,
"in_list_view": 0,
"label": "Contact Name",
"label": "Person Name",
"oldfieldname": "lead_name",
"oldfieldtype": "Data",
"permlevel": 0,
@@ -344,7 +344,7 @@
],
"icon": "icon-user",
"idx": 1,
"modified": "2015-04-02 15:13:02.621854",
"modified": "2015-07-03 03:26:18.579905",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",

View File

@@ -75,8 +75,7 @@ class Lead(SellingController):
return frappe.db.get_value("Customer", {"lead_name": self.name})
def has_opportunity(self):
return frappe.db.get_value("Opportunity", {"lead": self.name, "docstatus": 1,
"status": ["!=", "Lost"]})
return frappe.db.get_value("Opportunity", {"lead": self.name, "status": ["!=", "Lost"]})
@frappe.whitelist()
def make_customer(source_name, target_doc=None):

View File

@@ -52,7 +52,7 @@
"fieldtype": "Text Editor",
"label": "Message",
"permlevel": 0,
"reqd": 0
"reqd": 1
},
{
"description": "",
@@ -78,7 +78,7 @@
],
"icon": "icon-envelope",
"idx": 1,
"modified": "2015-03-20 05:27:31.613881",
"modified": "2015-07-20 05:43:33.818567",
"modified_by": "Administrator",
"module": "CRM",
"name": "Newsletter",

View File

@@ -32,6 +32,7 @@
"default": "0",
"fieldname": "total_subscribers",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Total Subscribers",
"permlevel": 0,
"precision": "",
@@ -45,7 +46,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"modified": "2015-03-18 08:08:37.692367",
"modified": "2015-07-15 07:18:30.094155",
"modified_by": "Administrator",
"module": "CRM",
"name": "Newsletter List",

View File

@@ -12,8 +12,8 @@ from email.utils import parseaddr
class NewsletterList(Document):
def onload(self):
singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})]
self.get("__onload").import_types = [d.parent \
for d in frappe.db.get_all("DocField", "parent", {"options": "Email"}) if d.parent not in singles]
self.get("__onload").import_types = [{"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} \
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"}) if d.parent not in singles]
def import_from(self, doctype):
"""Extract email ids from given doctype and add them to the current list"""

View File

@@ -79,7 +79,8 @@ class Opportunity(TransactionBase):
if self.customer:
self.customer_name = frappe.db.get_value("Customer", self.customer, "customer_name")
elif self.lead:
self.customer_name = frappe.db.get_value("Lead", self.lead, "lead_name")
lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"])
self.customer_name = company_name or lead_name
def get_cust_address(self,name):
details = frappe.db.sql("""select customer_name, address, territory, customer_group

View File

@@ -1,11 +1,34 @@
from __future__ import unicode_literals
app_name = "erpnext"
app_title = "ERPNext"
app_publisher = "Frappe Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_publisher = "Frappe Technologies Pvt. Ltd."
app_description = """## ERPNext
ERPNext is a fully featured ERP system designed for Small and Medium Sized
business. ERPNext covers a wide range of features including Accounting, CRM,
Inventory management, Selling, Purchasing, Manufacturing, Projects, HR &
Payroll, Website, E-Commerce and much more.
ERPNext is based on the Frappe Framework is highly customizable and extendable.
You can create Custom Form, Fields, Scripts and can also create your own Apps
to extend ERPNext functionality.
ERPNext is Open Source under the GNU General Public Licence v3 and has been
listed as one of the Best Open Source Softwares in the world by my online
blogs.
### Links
- Website: [https://erpnext.com](https://erpnext.com)
- GitHub: [https://github.com/frappe/erpnext](https://github.com/frappe/erpnext)
- Forum: [https://discuss.erpnext.com](https://discuss.erpnext.com)
- Frappe Framework: [https://frappe.io](https://frappe.io)
"""
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "5.0.20"
app_version = "5.3.0"
github_link = "https://github.com/frappe/erpnext"
error_report_email = "support@erpnext.com"
@@ -25,8 +48,13 @@ on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
# website
update_website_context = "erpnext.shopping_cart.utils.update_website_context"
my_account_context = "erpnext.shopping_cart.utils.update_my_account_context"
email_append_to = ["Job Applicant", "Opportunity", "Issue"]
calendars = ["Task", "Production Order", "Time Log", "Leave Application"]
website_generators = ["Item Group", "Item", "Sales Partner"]
website_context = {
"favicon": "/assets/erpnext/images/favicon.png",
"splash_image": "/assets/erpnext/images/splash.png"
@@ -52,14 +80,10 @@ dump_report_map = "erpnext.startup.report_data_map.data_map"
before_tests = "erpnext.setup.utils.before_tests"
website_generators = ["Item Group", "Item", "Sales Partner"]
standard_queries = {
"Customer": "erpnext.selling.doctype.customer.customer.get_customer_list"
}
communication_covert_to = ["Lead", "Issue", "Job Application"]
doc_events = {
"Stock Entry": {
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
@@ -78,8 +102,10 @@ doc_events = {
}
scheduler_events = {
"hourly": [
"erpnext.controllers.recurring_document.create_recurring_documents"
],
"daily": [
"erpnext.controllers.recurring_document.create_recurring_documents",
"erpnext.stock.reorder_item.reorder_item",
"erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.support.doctype.issue.issue.auto_close_tickets",
@@ -104,4 +130,3 @@ get_translated_dict = {
("page", "setup-wizard"): "frappe.geo.country_info.get_translated_dict",
("doctype", "Global Defaults"): "frappe.geo.country_info.get_translated_dict"
}

View File

@@ -290,6 +290,7 @@
"label": "Company Email",
"oldfieldname": "company_email",
"oldfieldtype": "Data",
"options": "Email",
"permlevel": 0,
"reqd": 0
},
@@ -385,6 +386,7 @@
"fieldname": "personal_email",
"fieldtype": "Data",
"label": "Personal Email",
"options": "Email",
"permlevel": 0
},
{
@@ -674,7 +676,7 @@
],
"icon": "icon-user",
"idx": 1,
"modified": "2015-02-20 05:02:14.205144",
"modified": "2015-07-09 02:25:20.987412",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",

View File

@@ -45,6 +45,10 @@ class Employee(Document):
if self.user_id:
self.validate_for_enabled_user_id()
self.validate_duplicate_user_id()
else:
existing_user_id = frappe.db.get_value("Employee", self.name, "user_id")
if existing_user_id:
frappe.permissions.remove_user_permission("Employee", self.name, existing_user_id)
def on_update(self):
if self.user_id:

View File

@@ -19,10 +19,13 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
jv.company = cur_frm.doc.company;
jv.remark = 'Payment against Expense Claim: ' + cur_frm.doc.name;
jv.fiscal_year = cur_frm.doc.fiscal_year;
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
d1.debit = cur_frm.doc.total_sanctioned_amount;
d1.against_expense_claim = cur_frm.doc.name;
var expense = cur_frm.doc.expenses || [];
for(var i = 0; i < expense.length; i++){
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
d1.debit = expense[i].sanctioned_amount;
d1.account = expense[i].default_account;
d1.against_expense_claim = cur_frm.doc.name;
}
// credit to bank
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
@@ -43,6 +46,7 @@ $.extend(cur_frm.cscript, new erpnext.hr.ExpenseClaimController({frm: cur_frm}))
cur_frm.add_fetch('employee', 'company', 'company');
cur_frm.add_fetch('employee','employee_name','employee_name');
cur_frm.add_fetch('expense_type', 'default_account', 'default_account');
cur_frm.cscript.onload = function(doc,cdt,cdn) {
if(!doc.approval_status)
@@ -63,7 +67,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn) {
cur_frm.set_query("exp_approver", function() {
return {
filters: [["UserRole", "role", "=", "Expense Approver"]]
query: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_approver"
};
});
}

View File

@@ -58,4 +58,13 @@ class ExpenseClaim(Document):
def validate_sanctioned_amount(self):
for d in self.get('expenses'):
if flt(d.sanctioned_amount) > flt(d.claim_amount):
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
@frappe.whitelist()
def get_expense_approver(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""
select u.name, concat(u.first_name, ' ', u.last_name)
from tabUser u, tabUserRole r
where u.name = r.parent and r.role = 'Expense Approver' and u.name like %s
""", ("%" + txt + "%"))

View File

@@ -34,6 +34,18 @@
"reqd": 1,
"width": "150px"
},
{
"depends_on": "expense_type",
"fieldname": "default_account",
"fieldtype": "Link",
"hidden": 1,
"label": "Default Account",
"options": "Account",
"permlevel": 0,
"precision": "",
"read_only": 1,
"unique": 0
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break",
@@ -93,7 +105,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-04-08 06:18:47.539134",
"modified": "2015-07-16 06:13:32.090048",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Detail",

View File

@@ -17,6 +17,14 @@
"reqd": 1,
"search_index": 0
},
{
"fieldname": "default_account",
"fieldtype": "Link",
"label": "Default Account",
"options": "Account",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "description",
"fieldtype": "Small Text",
@@ -29,7 +37,7 @@
],
"icon": "icon-flag",
"idx": 1,
"modified": "2015-04-19 06:47:51.860833",
"modified": "2015-07-15 08:57:23.069980",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Type",

View File

@@ -339,6 +339,7 @@ def add_block_dates(events, start, end, employee, company):
events.append({
"doctype": "Leave Block List Date",
"from_date": block_date.block_date,
"to_date": block_date.block_date,
"title": _("Leave Blocked") + ": " + block_date.reason,
"name": "_" + str(cnt),
})
@@ -355,6 +356,7 @@ def add_holidays(events, start, end, employee, company):
events.append({
"doctype": "Holiday",
"from_date": holiday.holiday_date,
"to_date": holiday.holiday_date,
"title": _("Holiday") + ": " + cstr(holiday.description),
"name": holiday.name
})

View File

@@ -1,30 +1,44 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
var display_activity_log = function(msg) {
cur_frm.cscript.display_activity_log = function(msg) {
if(!cur_frm.ss_html)
cur_frm.ss_html = $a(cur_frm.fields_dict['activity_log'].wrapper,'div');
cur_frm.ss_html.innerHTML =
'<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
if(msg) {
cur_frm.ss_html.innerHTML =
'<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
} else {
cur_frm.ss_html.innerHTML = "";
}
}
//Create salary slip
//-----------------------
cur_frm.cscript.create_salary_slip = function(doc, cdt, cdn) {
cur_frm.cscript.display_activity_log("");
var callback = function(r, rt){
if (r.message)
display_activity_log(r.message);
cur_frm.cscript.display_activity_log(r.message);
}
return $c('runserverobj', args={'method':'create_sal_slip','docs':doc},callback);
}
cur_frm.cscript.submit_salary_slip = function(doc, cdt, cdn) {
cur_frm.cscript.display_activity_log("");
var check = confirm(__("Do you really want to Submit all Salary Slip for month {0} and year {1}", [doc.month, doc.fiscal_year]));
if(check){
// clear all in locals
if(locals["Salary Slip"]) {
$.each(locals["Salary Slip"], function(name, d) {
frappe.model.remove_from_locals("Salary Slip", name);
});
}
var callback = function(r, rt){
if (r.message)
display_activity_log(r.message);
cur_frm.cscript.display_activity_log(r.message);
}
return $c('runserverobj', args={'method':'submit_salary_slip','docs':doc},callback);
}
}
@@ -45,6 +59,6 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) {
}
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
frappe.ui.form.on("Process Payroll", "refresh", function(frm) {
frm.disable_save();
});
});

View File

@@ -154,10 +154,10 @@
"icon": "icon-cog",
"idx": 1,
"issingle": 1,
"modified": "2015-06-05 11:33:00.152362",
"modified": "2015-07-07 07:16:02.380839",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Manager",
"name": "Process Payroll",
"owner": "Administrator",
"permissions": [
{

View File

@@ -8,7 +8,7 @@ from frappe import _
from frappe.model.document import Document
class SalaryManager(Document):
class ProcessPayroll(Document):
def get_emp_list(self):
"""
@@ -101,7 +101,7 @@ class SalaryManager(Document):
log = "<p>No employee for the above selected criteria OR salary slip already created</p>"
if ss_list:
log = "<b>Salary Slip Created For</b>\
<br><br>%s" % '<br>'.join(ss_list)
<br><br>%s" % '<br>'.join(self.format_as_links(ss_list))
return log
@@ -144,7 +144,7 @@ class SalaryManager(Document):
else:
all_ss = [d[0] for d in all_ss]
submitted_ss = list(set(all_ss) - set(not_submitted_ss))
submitted_ss = self.format_as_links(list(set(all_ss) - set(not_submitted_ss)))
if submitted_ss:
mail_sent_msg = self.send_email and " (Mail has been sent to the employee)" or ""
log = """
@@ -164,6 +164,9 @@ class SalaryManager(Document):
"""% ('<br>'.join(not_submitted_ss))
return log
def format_as_links(self, ss_list):
return ['<a href="#Form/Salary Slip/{0}">{0}</a>'.format(s) for s in ss_list]
def get_total_salary(self):
"""

View File

@@ -1 +0,0 @@
Tool to issue monthly Salary Slips to all Employees.

View File

@@ -1,21 +0,0 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Frappe Technologies Pvt Ltd
#
# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from frappe import ValidationError
class SalarySlipExistsError(ValidationError): pass

View File

@@ -49,7 +49,7 @@ class SalarySlip(TransactionBase):
if not self.month:
self.month = "%02d" % getdate(nowdate()).month
m = frappe.get_doc('Salary Manager').get_month_details(self.fiscal_year, self.month)
m = frappe.get_doc('Process Payroll').get_month_details(self.fiscal_year, self.month)
holidays = self.get_holidays_for_employee(m)
if not cint(frappe.db.get_value("HR Settings", "HR Settings",

View File

@@ -31,7 +31,7 @@
"fieldname": "d_depends_on_lwp",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Depends on LWP",
"label": "Depends on Leave Without Pay",
"permlevel": 0,
"print_hide": 1
},
@@ -46,7 +46,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-03-03 12:41:04.505378",
"modified": "2015-07-07 07:13:11.919941",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip Deduction",

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