Compare commits

..

139 Commits

Author SHA1 Message Date
mbauskar
ea92682cfd Merge branch 'hotfix' 2017-07-01 14:16:46 +05:30
mbauskar
af9d3a4db6 bumped to version 8.2.3 2017-07-01 14:46:46 +06:00
Makarand Bauskar
f39a9f1c5b Merge pull request #9562 from mbauskar/gst-hsn-code
[minor] fix autoname for GST HSN Code (#9536)
2017-07-01 14:15:18 +05:30
Sagar Vora
067991ee30 [minor] fix autoname for GST HSN Code (#9536) 2017-07-01 14:14:14 +05:30
rohitwaghchaure
6691856d08 Merge pull request #9554 from mbauskar/sales-register
[minor] fixed AttributeError: 'dict' object has no attribute 'company' in sales register
2017-06-30 16:48:10 +05:30
mbauskar
22aaf0cbd0 [minor] fixed AttributeError: 'dict' object has no attribute 'company' in sales register 2017-06-30 16:43:25 +05:30
mbauskar
943637e06c Merge branch 'hotfix' 2017-06-30 12:00:23 +05:30
mbauskar
0407cb0d92 bumped to version 8.2.2 2017-06-30 12:30:22 +06:00
Makarand Bauskar
d192a420d1 Merge pull request #9549 from rohitwaghchaure/patch_fix_gst
[Fix] Options must be a valid DocType for field Customs Tariff Number
2017-06-30 11:59:47 +05:30
Rohit Waghchaure
3856d14ae6 [Fix] Options must be a valid DocType for field Customs Tariff Number 2017-06-30 11:57:41 +05:30
mbauskar
4e08dfc72f Merge branch 'develop' 2017-06-29 21:58:08 +05:30
mbauskar
53e34f5c1c bumped to version 8.2.1 2017-06-29 22:28:08 +06:00
Makarand Bauskar
c6e1c3c048 Merge pull request #9537 from mbauskar/patch
[minor] fixed the report value for  deprecated report patch
2017-06-29 21:57:09 +05:30
mbauskar
0c2de6e07a [minor] fixed the report value for deprecated report patch 2017-06-29 21:47:14 +05:30
mbauskar
1508267fd6 Merge branch 'develop' 2017-06-29 15:07:26 +05:30
mbauskar
8f1f93603d bumped to version 8.2.0 2017-06-29 15:37:26 +06:00
Aditya Duggal
f1bd39c937 Allow NA values in GSTIN number (#9503)
-Reason for allowing NA value is that if a user wants to make GSTIN number mandatory then they can do the same easily
2017-06-29 14:25:19 +05:30
mbauskar
ec252c806f resolved merge conflicts 2017-06-29 12:11:07 +05:30
mbauskar
2a903a0608 Merge branch 'hotfix' 2017-06-29 12:09:40 +05:30
mbauskar
71b4e48ea5 bumped to version 8.1.7 2017-06-29 12:39:39 +06:00
Makarand Bauskar
ae2d92ee76 Merge pull request #9523 from saurabh6790/setup_wiz_fix
[fix] translate domain
2017-06-29 12:07:19 +05:30
Saurabh
21cf1fd851 [fix] translate domain 2017-06-29 12:04:45 +05:30
Makarand Bauskar
02c281cc2f Merge pull request #9522 from rmehta/update-gstin-2
[fix] update-gstin
2017-06-29 12:01:20 +05:30
Makarand Bauskar
a938d3956a [minor] get doc using party_name instead of party 2017-06-29 11:58:50 +05:30
Rushabh Mehta
02b0ed4199 [fix] update-gstin 2017-06-29 11:56:14 +05:30
Vishal Dhayagude
76f93d05b7 display image in supplier's list view (#9500)
* [fix]display supplier image in desk

* Supplier image displayed in desk

* Show image in supplier desk page

* [minor] removed whitespaces
2017-06-29 11:23:13 +05:30
Makarand Bauskar
24ab20fe11 Merge pull request #9467 from rohitwaghchaure/support_hours_report
[enhance] Report for analysis of support hours count
2017-06-29 11:19:41 +05:30
Makarand Bauskar
1eb31db71f Merge pull request #9466 from manassolanki/validation
changes in student settings for validating the students in the student groups
2017-06-29 10:48:59 +05:30
Makarand Bauskar
ef95b4d6e3 Merge pull request #9468 from manassolanki/issue-11
in program enrollment filter out students which are already enrolled
2017-06-29 10:48:12 +05:30
Makarand Bauskar
514c0417dd Merge pull request #9483 from manassolanki/fix-student-fetch
fetch queries for the students in the student group
2017-06-29 10:47:05 +05:30
Makarand Bauskar
67f6ac848c Merge pull request #9497 from ashwinisave35/email_template_redesign
Adding ERPNext logo for email templates.
2017-06-29 10:46:44 +05:30
Makarand Bauskar
5d95ebec4e Merge pull request #9508 from rohitwaghchaure/contacts_module_error
[Fix] Module error during patch execution
2017-06-29 10:46:17 +05:30
Makarand Bauskar
bb7317d398 Merge pull request #9512 from mbauskar/patch-fix
[fixes] delete auto email report of deprecated reports and other minor fixes
2017-06-29 10:45:50 +05:30
Makarand Bauskar
550268eaf3 Merge pull request #9518 from sagarvora/gh-9516
[minor] fix supplier GSTIN portal not getting displayed
2017-06-29 10:43:53 +05:30
Makarand Bauskar
7f9af46da5 [minor] removed whitespace 2017-06-29 09:38:46 +05:30
Makarand Bauskar
e38eb83358 [minor] removed print statement 2017-06-29 09:35:11 +05:30
Makarand Bauskar
af00c9f70b [minor] removed whitespaces from get_students method 2017-06-29 09:25:19 +05:30
Makarand Bauskar
5c7545da0c [minor] passed index for string format 2017-06-29 09:07:59 +05:30
mbauskar
d6e8bb5452 [fixes] delete auto email report of deprecated reports and other minor fixes 2017-06-29 08:39:01 +05:30
Sagar Vora
435032f5bc [minor] fix typo 2017-06-28 23:59:47 +05:30
Sagar Vora
1ef50c89db [minor] use party_name instead of party and save GSTIN in uppercase 2017-06-28 23:52:22 +05:30
Rohit Waghchaure
2e4b4454b3 [Fix] Module error during patch execution 2017-06-28 17:31:59 +05:30
rohitwaghchaure
4b33b7e1c1 Merge pull request #9418 from nick9822/nick9822-patch-3
Removed "Asset" filter on payment account
2017-06-28 16:38:21 +05:30
rohitwaghchaure
69279229cc Merge pull request #8987 from bcornwellmott/bom_convert_uom
Added BOM UOM selection for items
2017-06-28 16:28:31 +05:30
Rohit Waghchaure
5b7028c7bb stock qty not changed if item change 2017-06-28 15:58:51 +05:30
mbauskar
0018db344c Merge branch 'develop' 2017-06-28 13:32:29 +05:30
mbauskar
e9a4f4e70d bumped to version 8.1.6 2017-06-28 14:02:29 +06:00
Saurabh
be03de3ad6 Merge pull request #9502 from mbauskar/patch-fix
[fix] delete/update desktop icon for deprecated report
2017-06-28 13:28:33 +05:30
Makarand Bauskar
d235325a95 Merge pull request #9501 from saurabh6790/gst_patch_fix
[fix] delete custom field tax_id if exists in transaction Sales Order, Sales Invoice and Delivery Note
2017-06-28 13:28:02 +05:30
mbauskar
6daa6e422e [fix] delete/update desktop icon for deprecated report 2017-06-28 13:26:50 +05:30
Saurabh
07913c3ff2 [fix] delete custom field tax_id if exists in trasaction Sales Order, Sales Invoice and Delivery Note 2017-06-28 13:16:50 +05:30
Makarand Bauskar
71ba7ea717 Merge pull request #9498 from mbauskar/develop
[minor] fixed broken image url in gst documentation
2017-06-28 12:30:56 +05:30
mbauskar
3b0e6cecd6 [minor] fixed broken image url in gst documentation 2017-06-28 12:29:19 +05:30
Ashwini Save
544de60d36 Adding ERPNext logo for email tempates. 2017-06-28 11:44:09 +05:30
Manas Solanki
d652221071 fetch queries for the students in the student group 2017-06-28 11:26:41 +05:30
mbauskar
4d5d3b7685 Merge branch 'develop' 2017-06-28 11:01:40 +05:30
mbauskar
3bf9071598 bumped to version 8.1.5 2017-06-28 11:31:40 +06:00
Saurabh
46af07cc09 Merge pull request #9494 from mbauskar/patch-fixes
[fix] handle email exception if email account is not configured
2017-06-28 11:00:00 +05:30
mbauskar
27692670b1 [fix] handle email exception if email account is not configured 2017-06-28 10:56:50 +05:30
Makarand Bauskar
3708df61bf Merge pull request #9493 from saurabh6790/gst_patch_fix
[fix] reload gst settings doctype in patch
2017-06-28 10:52:49 +05:30
Saurabh
3f2dd04b10 [fix] reload gst settings doctype in patch 2017-06-28 10:50:38 +05:30
mbauskar
fd598d8f3a Merge branch 'develop' 2017-06-28 10:40:07 +05:30
mbauskar
4e0999dda7 bumped to version 8.1.4 2017-06-28 11:10:07 +06:00
Makarand Bauskar
eef3f62ff7 Merge pull request #9488 from rmehta/gst-reminder
[regional] ability to send gst reminders to all parties
2017-06-27 19:33:05 +05:30
Makarand Bauskar
104eb8c6ad [minor] render GSTIN value as "" instead of None 2017-06-27 18:59:35 +05:30
Manas Solanki
3959c7c3c1 filter out students which are already enrolled in program enrollment 2017-06-27 18:22:05 +05:30
Makarand Bauskar
b43f4073db fixed TypeError: throw() got an unexpected keyword argument 'exception' 2017-06-27 18:15:52 +05:30
Rushabh Mehta
01659271be [minor] dont make fixtures again by patch 2017-06-27 18:05:54 +05:30
Rushabh Mehta
c616a4a527 [tests] codacy 2017-06-27 17:50:15 +05:30
Rushabh Mehta
00ae424cac [regional] ability to send gst reminders to all parties 2017-06-27 17:31:41 +05:30
Makarand Bauskar
7b6e09b9a7 Merge pull request #9487 from rohitwaghchaure/currency_label_issue
[fix] Currency label not displaying in the total advance field
2017-06-27 16:16:22 +05:30
Makarand Bauskar
90a3e60de7 Merge pull request #9372 from pratu16x7/serial-batch-entry
Serial no/batch entry dialog
2017-06-27 16:12:30 +05:30
Rohit Waghchaure
f3e91e2b2b [minor] Currency label not displaying in the total advance field 2017-06-27 15:51:35 +05:30
pratu16x7
846f5d4bd8 [fix] cloning rows 2017-06-27 14:03:56 +05:30
Makarand Bauskar
51520f9de6 Merge pull request #9479 from frappe-pr-bot/translations-2017-06-27
[translation] translation update
2017-06-27 13:58:04 +05:30
Makarand Bauskar
9d457d3e34 Merge pull request #9485 from saurabh6790/gst_update_email
send email to system managers about gst update
2017-06-27 13:42:52 +05:30
frappe-pr-bot
8ddd946dea [translation] translation updates 2017-06-27 10:10:50 +02:00
Saurabh
c20abf6b2a send email to system managers about gst setup 2017-06-27 13:21:57 +05:30
Makarand Bauskar
68a48c9cfc Merge pull request #9484 from mbauskar/develop
revert customer-orders-invoices-and-shipping-status.md documentation
2017-06-27 12:51:32 +05:30
mbauskar
8c3f99f12e revert customer-orders-invoices-and-shipping-status.md documentation 2017-06-27 12:49:10 +05:30
Rushabh Mehta
9b09ff29d2 [fix] address creation for india/setup.py 2017-06-27 12:17:39 +05:30
Rushabh Mehta
f4e908bd91 [minor] general_ledger.js 2017-06-27 11:56:30 +05:30
Makarand Bauskar
5d8803b23e Merge pull request #9435 from rmehta/gst
GST (India) Setup and Invoices #8711
2017-06-27 11:44:33 +05:30
pratu16x7
f970ca4d35 Update docs 2017-06-27 10:12:58 +05:30
pratu16x7
29cebbb0cd use set_value() for setting rows 2017-06-27 09:48:28 +05:30
pratu16x7
89d001caf3 [lint] fixes 2017-06-26 17:45:49 +05:30
Rohit Waghchaure
67526f244e [enhance] Report for analysis of support hours count 2017-06-26 17:04:52 +05:30
pratu16x7
ae450fc23b async call to require, more validation 2017-06-26 15:31:46 +05:30
nick9822
82e816054e Added report_type to payment account filter 2017-06-26 15:29:44 +05:30
Manas Solanki
cb650f836e validation of student in student attendance 2017-06-26 14:11:12 +05:30
Saurabh
f4fc30a72d Merge branch 'develop' 2017-06-26 13:55:59 +05:30
Saurabh
095701e86b bumped to version 8.1.3 2017-06-26 14:25:59 +06:00
Saurabh
dccceb44f9 Merge pull request #9463 from saurabh6790/v8_1_patch_fixes
[fix] patch fixes
2017-06-26 13:52:23 +05:30
pratu16x7
5f389c999a [fix] values update in items in invoices 2017-06-26 13:38:24 +05:30
Saurabh
29fa0a9a17 [fix] patch fixes 2017-06-26 13:28:45 +05:30
pratu16x7
577e4c4e28 Add in transaction.js, cleanups 2017-06-23 19:25:01 +05:30
Rushabh Mehta
210b6f8f7e [docs] 2017-06-22 22:32:08 +05:30
Rushabh Mehta
25366a22ad [minor] cleanup 2017-06-22 22:32:08 +05:30
Rushabh Mehta
919a74ad88 [gst] adde reports + docs 2017-06-22 22:32:08 +05:30
Rushabh Mehta
b3c8f44b3e [wip] GST for India. Pending reports 2017-06-22 22:31:32 +05:30
pratu16x7
759f669214 Add in delivery note 2017-06-22 18:14:29 +05:30
pratu16x7
70eca9462b make erpnext.SerialNoBatchSelector 2017-06-22 18:14:29 +05:30
pratu16x7
60d9446656 onchange in df 2017-06-22 18:14:29 +05:30
pratu16x7
934105bf34 fix modified by, blur serial field 2017-06-22 18:14:28 +05:30
pratu16x7
26b8f5c3ce [minor] 2017-06-22 18:14:16 +05:30
pratu16x7
36693e27be [fix] tests 2017-06-22 18:14:16 +05:30
pratu16x7
a5d5403bf3 specific change bubbling for grid fields 2017-06-22 18:13:56 +05:30
pratu16x7
0e35651e94 Add get_stock_qty test 2017-06-22 18:13:56 +05:30
pratu16x7
837ffbddbc [minor] 2017-06-22 18:13:55 +05:30
pratu16x7
ff25573558 cleanup 2017-06-22 18:13:55 +05:30
pratu16x7
82a199d6d7 [fix] availably qty reupdate 2017-06-22 18:13:55 +05:30
pratu16x7
d15a507567 add serial_no_check 2017-06-22 18:13:55 +05:30
pratu16x7
01e79f033e add warehouse selection and mapping 2017-06-22 18:13:55 +05:30
pratu16x7
9a6e675b41 wip 2017-06-22 18:13:55 +05:30
pratu16x7
7331f169fc [fix] warehouse required bug 2017-06-22 18:13:54 +05:30
pratu16x7
d09f35fa98 fire modal on item_code, events, validation 2017-06-22 18:13:54 +05:30
pratu16x7
52d703a232 [fix] test 2017-06-22 18:13:54 +05:30
pratu16x7
e4e00d2215 batch item distribution by oldest, serial no check 2017-06-22 18:13:54 +05:30
pratu16x7
60944e3397 get oldest batch in modal, insert batch items 2017-06-22 18:13:30 +05:30
pratu16x7
0b642cd414 set available qty 2017-06-22 18:13:30 +05:30
pratu16x7
b4de1c771b WIP 2017-06-22 18:13:30 +05:30
Rushabh Mehta
aedaac63ea [wip] batch, serial number selector 2017-06-22 18:13:30 +05:30
Ben Cornwell-Mott
ac3ad0810a Merge branch 'bom_convert_uom' of https://github.com/bcornwellmott/erpnext into bom_convert_uom 2017-06-21 10:17:39 -07:00
Ben Cornwell-Mott
1e96b7bbe5 Added conversion_factor update in patch 2017-06-21 10:16:50 -07:00
Makarand Bauskar
0ea5d941e6 Merge branch 'develop' into bom_convert_uom 2017-06-21 21:35:38 +05:30
nick9822
881491cd2b Removed "Asset" filter on payment account 2017-06-21 19:51:08 +05:30
Ben Cornwell-Mott
2c77165fc6 Fixed small code issues (codecy) 2017-06-16 13:47:40 -07:00
bcornwellmott
6561b8ade9 Merge branch 'develop' into bom_convert_uom 2017-06-16 08:29:00 -07:00
Ben Cornwell-Mott
840c757b12 Merge branch 'bom_convert_uom' of https://github.com/bcornwellmott/erpnext into bom_convert_uom 2017-06-15 08:53:29 -07:00
Ben Cornwell-Mott
7055446508 Reload explosion and scrap items docs 2017-06-15 08:52:55 -07:00
Rushabh Mehta
e0434ad40e Merge branch 'develop' into bom_convert_uom 2017-06-15 17:32:27 +05:30
bcornwellmott
d53dd7f4c9 Merge branch 'develop' into bom_convert_uom 2017-06-13 08:40:24 -07:00
bcornwellmott
fed9816213 Removed trailing whitespace 2017-06-09 07:37:27 -07:00
bcornwellmott
a35839aa47 Removing unused pprint 2017-06-09 07:36:15 -07:00
bcornwellmott
5491275b66 Merge branch 'develop' into bom_convert_uom 2017-06-07 08:42:54 -07:00
Ben Cornwell-Mott
70fe968f02 Fixed some errors 2017-06-04 20:19:59 -07:00
Ben Cornwell-Mott
a3aa6a4449 Changed Explosion Item as well 2017-06-02 16:54:03 -07:00
bcornwellmott
8fa1e03367 Merge branch 'develop' into bom_convert_uom 2017-05-24 12:35:12 -07:00
Ben Cornwell-Mott
0f0b121669 Added BOM UOM selection for items
Added patch for BOM Item UOM

Fixed scrap qty issue

Added Scrap Qty update to patch

Reverted test record for production order
2017-05-24 11:12:51 -07:00
148 changed files with 56980 additions and 4143 deletions

View File

@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
__version__ = '8.1.2'
__version__ = '8.2.3'
def get_default_company(user=None):

View File

@@ -224,9 +224,9 @@ cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
return {
filters: [
["Account", "account_type", "in", ["Cash", "Bank"]],
["Account", "root_type", "=", "Asset"],
["Account", "is_group", "=",0],
["Account", "company", "=", doc.company]
["Account", "company", "=", doc.company],
["Account", "report_type", "=", "Balance Sheet"]
]
}
}

View File

@@ -502,8 +502,20 @@ frappe.ui.form.on('Sales Invoice', {
}
}
}
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(_('Please set Company'));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
link_doctype: 'Company',
link_name: doc.company
}
};
});
},
project: function(frm){

View File

@@ -940,22 +940,22 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "customer_group",
"fieldname": "company_address",
"fieldtype": "Link",
"hidden": 1,
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Customer Group",
"label": "Company Address",
"length": 0,
"no_copy": 0,
"options": "Customer Group",
"options": "Address",
"permlevel": 0,
"print_hide": 1,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -3489,6 +3489,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Customer Group",
"length": 0,
"no_copy": 0,
"options": "Customer Group",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -4596,7 +4627,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-16 17:07:55.483734",
"modified": "2017-06-22 14:45:35.257640",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -7,11 +7,12 @@ import frappe
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.model.utils import get_fetch_values
from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, \
add_years, get_timestamp, nowdate, flt
from frappe.contacts.doctype.address.address import get_address_display, get_default_address
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, InvalidCurrency, PartyDisabled, InvalidAccountCurrency
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_default_currency
@@ -42,7 +43,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
party = frappe.get_doc(party_type, party)
set_address_details(out, party, party_type)
set_address_details(out, party, party_type, doctype, company)
set_contact_details(out, party, party_type)
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
@@ -60,10 +61,11 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
return out
def set_address_details(out, party, party_type):
def set_address_details(out, party, party_type, doctype=None, company=None):
billing_address_field = "customer_address" if party_type == "Lead" \
else party_type.lower() + "_address"
out[billing_address_field] = get_default_address(party_type, party.name)
out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
# address display
out.address_display = get_address_display(out[billing_address_field])
@@ -72,6 +74,11 @@ def set_address_details(out, party, party_type):
if party_type in ["Customer", "Lead"]:
out.shipping_address_name = get_default_address(party_type, party.name, 'is_shipping_address')
out.shipping_address = get_address_display(out["shipping_address_name"])
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
if doctype and doctype in ['Sales Invoice']:
out.company_address = get_default_address('Company', company)
out.update(get_fetch_values(doctype, 'company_address', out.company_address))
def set_contact_details(out, party, party_type):
out.contact_person = get_default_contact(party_type, party.name)
@@ -363,28 +370,28 @@ def get_timeline_data(doctype, name):
out.update({ timestamp: count })
return out
def get_dashboard_info(party_type, party):
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
company = frappe.db.get_default("company") or frappe.get_all("Company")[0].name
party_account_currency = get_party_account_currency(party_type, party, company)
company_default_currency = get_default_currency() \
or frappe.db.get_value('Company', company, 'default_currency')
if party_account_currency==company_default_currency:
total_field = "base_grand_total"
else:
total_field = "grand_total"
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
billing_this_year = frappe.db.sql("""
select sum({0})
from `tab{1}`
where {2}=%s and docstatus=1 and posting_date between %s and %s
""".format(total_field, doctype, party_type.lower()),
""".format(total_field, doctype, party_type.lower()),
(party, current_fiscal_year.year_start_date, current_fiscal_year.year_end_date))
total_unpaid = frappe.db.sql("""
select sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
@@ -396,5 +403,5 @@ def get_dashboard_info(party_type, party):
info["total_unpaid"] = flt(total_unpaid[0][0]) if total_unpaid else 0
if party_type == "Supplier":
info["total_unpaid"] = -1 * info["total_unpaid"]
return info

View File

@@ -75,7 +75,7 @@ frappe.query_reports["General Ledger"] = {
}
return party_type;
},
change: function() {
on_change: 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_type || !party) {

View File

@@ -7,11 +7,14 @@ from frappe import _
from frappe.utils import flt
def execute(filters=None):
return _execute(filters)
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {}
columns = get_columns()
columns = get_columns(additional_table_columns)
last_col = len(columns)
item_list = get_items(filters)
item_list = get_items(filters, additional_query_columns)
aii_account_map = get_aii_accounts()
if item_list:
item_row_tax, tax_accounts = get_tax_accounts(item_list, columns)
@@ -23,7 +26,7 @@ def execute(filters=None):
"width": 80
})
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
data = []
for d in item_list:
purchase_receipt = None
@@ -35,8 +38,16 @@ def execute(filters=None):
expense_account = d.expense_account or aii_account_map.get(d.company)
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date, d.supplier,
d.supplier_name, d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
purchase_receipt, expense_account, d.qty, d.base_net_rate, d.base_net_amount]
d.supplier_name]
if additional_query_columns:
for col in additional_query_columns:
row.append(d.get(col))
row += [
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
purchase_receipt, expense_account, d.qty, d.base_net_rate, d.base_net_amount
]
for tax in tax_accounts:
row.append(item_row_tax.get(d.name, {}).get(tax, 0))
@@ -49,17 +60,27 @@ def execute(filters=None):
return columns, data
def get_columns():
return [_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
def get_columns(additional_table_columns):
columns = [
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
_("Item Group") + ":Link/Item Group:100", _("Invoice") + ":Link/Purchase Invoice:120",
_("Posting Date") + ":Date:80", _("Supplier") + ":Link/Supplier:120",
"Supplier Name::120", "Payable Account:Link/Account:120",
"Supplier Name::120"
]
if additional_table_columns:
columns += additional_table_columns
columns += [
"Payable Account:Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100",
_("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140",
_("Qty") + ":Float:120", _("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120"
]
return columns
def get_conditions(filters):
conditions = ""
@@ -74,21 +95,23 @@ def get_conditions(filters):
return conditions
def get_items(filters):
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Purchase Invoice")
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
return frappe.db.sql("""
select
select
pi_item.name, pi_item.parent, pi.posting_date, pi.credit_to, pi.company,
pi.supplier, pi.remarks, pi.base_net_total, pi_item.item_code, pi_item.item_name,
pi_item.item_group, pi_item.project, pi_item.purchase_order, pi_item.purchase_receipt,
pi_item.po_detail, pi_item.expense_account, pi_item.qty, pi_item.base_net_rate,
pi_item.base_net_amount, pi.supplier_name, pi.mode_of_payment
pi.supplier, pi.remarks, pi.base_net_total, pi_item.item_code, pi_item.item_name,
pi_item.item_group, pi_item.project, pi_item.purchase_order, pi_item.purchase_receipt,
pi_item.po_detail, pi_item.expense_account, pi_item.qty, pi_item.base_net_rate,
pi_item.base_net_amount, pi.supplier_name, pi.mode_of_payment {0}
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
where pi.name = pi_item.parent and pi.docstatus = 1 %s %s
order by pi.posting_date desc, pi_item.item_code desc
""" % (conditions, match_conditions), filters, as_dict=1)
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
def get_aii_accounts():
return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany"))
@@ -104,11 +127,11 @@ def get_tax_accounts(item_list, columns):
item_row_map.setdefault(d.parent, {}).setdefault(d.item_code, []).append(d)
tax_details = frappe.db.sql("""
select
select
parent, account_head, item_wise_tax_detail, charge_type, base_tax_amount_after_discount_amount
from `tabPurchase Taxes and Charges`
where parenttype = 'Purchase Invoice' and docstatus = 1
and (account_head is not null and account_head != '')
from `tabPurchase Taxes and Charges`
where parenttype = 'Purchase Invoice' and docstatus = 1
and (account_head is not null and account_head != '')
and category in ('Total', 'Valuation and Total')
and parent in (%s)
""" % ', '.join(['%s']*len(invoice_item_row)), tuple(invoice_item_row.keys()))
@@ -120,17 +143,17 @@ def get_tax_accounts(item_list, columns):
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
for item_code, tax_amount in item_wise_tax_detail.items():
tax_amount = flt(tax_amount[1]) if isinstance(tax_amount, list) else flt(tax_amount)
item_net_amount = sum([flt(d.base_net_amount)
item_net_amount = sum([flt(d.base_net_amount)
for d in item_row_map.get(parent, {}).get(item_code, [])])
for d in item_row_map.get(parent, {}).get(item_code, []):
item_tax_amount = flt((tax_amount * d.base_net_amount) / item_net_amount) if item_net_amount else 0
item_row_tax.setdefault(d.name, {})[account_head] = item_tax_amount
except ValueError:
continue
elif charge_type == "Actual" and tax_amount:

View File

@@ -8,11 +8,14 @@ from frappe.utils import flt
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
def execute(filters=None):
return _execute(filters)
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {}
columns = get_columns()
columns = get_columns(additional_table_columns)
last_col = len(columns)
item_list = get_items(filters)
item_list = get_items(filters, additional_query_columns)
if item_list:
item_row_tax, tax_accounts = get_tax_accounts(item_list, columns)
columns.append({
@@ -21,7 +24,7 @@ def execute(filters=None):
"fieldtype": "Data",
"width": 80
})
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency")
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
data = []
@@ -35,10 +38,17 @@ def execute(filters=None):
if not delivery_note and d.update_stock:
delivery_note = d.parent
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date, d.customer, d.customer_name,
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date, d.customer, d.customer_name]
if additional_query_columns:
for col in additional_query_columns:
row.append(d.get(col))
row += [
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
d.territory, d.project, d.company, d.sales_order,
delivery_note, d.income_account, d.cost_center, d.qty, d.base_net_rate, d.base_net_amount]
delivery_note, d.income_account, d.cost_center, d.qty, d.base_net_rate, d.base_net_amount
]
for tax in tax_accounts:
row.append(item_row_tax.get(d.name, {}).get(tax, 0))
@@ -50,12 +60,18 @@ def execute(filters=None):
return columns, data
def get_columns():
return [
def get_columns(additional_table_columns):
columns = [
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
_("Item Group") + ":Link/Item Group:100", _("Invoice") + ":Link/Sales Invoice:120",
_("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
_("Customer Name") + "::120", _("Customer Group") + ":Link/Customer Group:120",
_("Customer Name") + "::120"]
if additional_table_columns:
columns += additional_table_columns
columns += [
_("Customer Group") + ":Link/Customer Group:120",
_("Receivable Account") + ":Link/Account:120",
_("Mode of Payment") + "::120", _("Territory") + ":Link/Territory:80",
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
@@ -66,6 +82,8 @@ def get_columns():
_("Amount") + ":Currency/currency:120"
]
return columns
def get_conditions(filters):
conditions = ""
@@ -76,15 +94,18 @@ def get_conditions(filters):
("to_date", " and si.posting_date<=%(to_date)s")):
if filters.get(opts[0]):
conditions += opts[1]
if filters.get("mode_of_payment"):
conditions += """ and exists(select name from `tabSales Invoice Payment`
where parent=si.name
where parent=si.name
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
return conditions
def get_items(filters):
def get_items(filters, additional_query_columns):
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
conditions = get_conditions(filters)
return frappe.db.sql("""
select
@@ -93,10 +114,11 @@ def get_items(filters):
si_item.item_code, si_item.item_name, si_item.item_group, si_item.sales_order,
si_item.delivery_note, si_item.income_account, si_item.cost_center, si_item.qty,
si_item.base_net_rate, si_item.base_net_amount, si.customer_name,
si.customer_group, si_item.so_detail, si.update_stock
si.customer_group, si_item.so_detail, si.update_stock {0}
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 %s
order by si.posting_date desc, si_item.item_code desc""" % conditions, filters, as_dict=1)
order by si.posting_date desc, si_item.item_code desc
""".format(additional_query_columns or '') % conditions, filters, as_dict=1)
def get_tax_accounts(item_list, columns):
import json

View File

@@ -7,10 +7,13 @@ from frappe.utils import flt
from frappe import msgprint, _
def execute(filters=None):
return _execute(filters)
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {}
invoice_list = get_invoices(filters)
columns, expense_accounts, tax_accounts = get_columns(invoice_list)
invoice_list = get_invoices(filters, additional_query_columns)
columns, expense_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
@@ -20,8 +23,9 @@ def execute(filters=None):
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_expense_map, expense_accounts)
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
supplier_details = get_supplier_details(invoice_list)
suppliers = list(set([d.supplier for d in invoice_list]))
supplier_details = get_supplier_details(suppliers)
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
data = []
@@ -31,10 +35,18 @@ def execute(filters=None):
purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])))
project = list(set(invoice_po_pr_map.get(inv.name, {}).get("project", [])))
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name,
supplier_details.get(inv.supplier),
inv.credit_to, inv.mode_of_payment, ", ".join(project), inv.bill_no, inv.bill_date, inv.remarks,
", ".join(purchase_order), ", ".join(purchase_receipt), company_currency]
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name]
if additional_query_columns:
for col in additional_query_columns:
row.append(inv.get(col))
row += [
supplier_details.get(inv.supplier), # supplier_type
inv.credit_to, inv.mode_of_payment, ", ".join(project),
inv.bill_no, inv.bill_date, inv.remarks,
", ".join(purchase_order), ", ".join(purchase_receipt), company_currency
]
# map expense values
base_net_total = 0
@@ -61,15 +73,20 @@ def execute(filters=None):
return columns, data
def get_columns(invoice_list):
def get_columns(invoice_list, additional_table_columns):
"""return columns based on filters"""
columns = [
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80",
_("Supplier Id") + "::120", _("Supplier Name") + "::120",
_("Supplier Type") + ":Link/Supplier Type:120", _("Payable Account") + ":Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80",
_("Supplier Id") + "::120", _("Supplier Name") + "::120"]
if additional_table_columns:
columns += additional_table_columns
columns += [
_("Supplier Type") + ":Link/Supplier Type:120", _("Payable Account") + ":Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Bill No") + "::120", _("Bill Date") + ":Date:80", _("Remarks") + "::150",
_("Purchase Order") + ":Link/Purchase Order:100",
_("Purchase Order") + ":Link/Purchase Order:100",
_("Purchase Receipt") + ":Link/Purchase Receipt:100",
{
"fieldname": "currency",
@@ -114,27 +131,31 @@ def get_conditions(filters):
if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s"
if filters.get("to_date"): conditions += " and posting_date<=%(to_date)s"
if filters.get("mode_of_payment"): conditions += " and ifnull(mode_of_payment, '') = %(mode_of_payment)s"
return conditions
def get_invoices(filters):
def get_invoices(filters, additional_query_columns):
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
conditions = get_conditions(filters)
return frappe.db.sql("""
select
name, posting_date, credit_to, supplier, supplier_name, bill_no, bill_date, remarks,
base_net_total, base_grand_total, outstanding_amount, mode_of_payment
from `tabPurchase Invoice`
select
name, posting_date, credit_to, supplier, supplier_name, bill_no, bill_date,
remarks, base_net_total, base_grand_total, outstanding_amount,
mode_of_payment {0}
from `tabPurchase Invoice`
where docstatus = 1 %s
order by posting_date desc, name desc""" % conditions, filters, as_dict=1)
order by posting_date desc, name desc""".format(additional_query_columns or '') % conditions, filters, as_dict=1)
def get_invoice_expense_map(invoice_list):
expense_details = frappe.db.sql("""
select parent, expense_account, sum(base_net_amount) as amount
from `tabPurchase Invoice Item`
where parent in (%s)
from `tabPurchase Invoice Item`
where parent in (%s)
group by parent, expense_account
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
@@ -149,7 +170,7 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
tax_details = frappe.db.sql("""
select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount_after_discount_amount)
else sum(base_tax_amount_after_discount_amount) * -1 end as tax_amount
from `tabPurchase Taxes and Charges`
from `tabPurchase Taxes and Charges`
where parent in (%s) and category in ('Total', 'Valuation and Total')
group by parent, account_head, add_deduct_tax
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
@@ -169,8 +190,8 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
def get_invoice_po_pr_map(invoice_list):
pi_items = frappe.db.sql("""
select parent, purchase_order, purchase_receipt, po_detail, project
from `tabPurchase Invoice Item`
select parent, purchase_order, purchase_receipt, po_detail, project
from `tabPurchase Invoice Item`
where parent in (%s) and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
@@ -205,9 +226,8 @@ def get_account_details(invoice_list):
return account_map
def get_supplier_details(invoice_list):
def get_supplier_details(suppliers):
supplier_details = {}
suppliers = list(set([inv.supplier for inv in invoice_list]))
for supp in frappe.db.sql("""select name, supplier_type from `tabSupplier`
where name in (%s)""" % ", ".join(["%s"]*len(suppliers)), tuple(suppliers), as_dict=1):
supplier_details.setdefault(supp.name, supp.supplier_type)

View File

@@ -7,10 +7,13 @@ from frappe.utils import flt
from frappe import msgprint, _
def execute(filters=None):
return _execute(filters)
def _execute(filters, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = frappe._dict({})
invoice_list = get_invoices(filters)
columns, income_accounts, tax_accounts = get_columns(invoice_list)
invoice_list = get_invoices(filters, additional_query_columns)
columns, income_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
@@ -21,8 +24,9 @@ def execute(filters=None):
invoice_income_map, income_accounts)
invoice_so_dn_map = get_invoice_so_dn_map(invoice_list)
customer_map = get_customer_details(invoice_list)
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
customers = list(set([inv.customer for inv in invoice_list]))
customer_map = get_customer_details(customers)
company_currency = frappe.db.get_value("Company", filters.get("company"), "default_currency")
mode_of_payments = get_mode_of_payments([inv.name for inv in invoice_list])
data = []
@@ -31,12 +35,22 @@ def execute(filters=None):
sales_order = list(set(invoice_so_dn_map.get(inv.name, {}).get("sales_order", [])))
delivery_note = list(set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", [])))
row = [inv.name, inv.posting_date, inv.customer, inv.customer_name,
customer_map.get(inv.customer, {}).get("customer_group"),
customer_map.get(inv.customer, {}).get("territory"),
inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])), inv.project, inv.remarks,
", ".join(sales_order), ", ".join(delivery_note), company_currency]
customer_details = customer_map.get(inv.customer, {})
row = [
inv.name, inv.posting_date, inv.customer, inv.customer_name
]
if additional_query_columns:
for col in additional_query_columns:
row.append(inv.get(col))
row +=[
customer_details.get("customer_group"),
customer_details.get("territory"),
inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
inv.project, inv.remarks,
", ".join(sales_order), ", ".join(delivery_note), company_currency
]
# map income values
base_net_total = 0
for income_acc in income_accounts:
@@ -62,15 +76,20 @@ def execute(filters=None):
return columns, data
def get_columns(invoice_list):
def get_columns(invoice_list, additional_table_columns):
"""return columns based on filters"""
columns = [
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
_("Customer Id") + "::120", _("Customer Name") + "::120",
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
_("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
_("Project") +":Link/Project:80", _("Remarks") + "::150",
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
_("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
]
if additional_table_columns:
columns += additional_table_columns
columns +=[
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
_("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
_("Project") +":Link/Project:80", _("Remarks") + "::150",
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
{
"fieldname": "currency",
@@ -113,20 +132,23 @@ def get_conditions(filters):
if filters.get("from_date"): conditions += " and posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and posting_date <= %(to_date)s"
if filters.get("mode_of_payment"):
conditions += """ and exists(select name from `tabSales Invoice Payment`
where parent=`tabSales Invoice`.name
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
return conditions
def get_invoices(filters):
def get_invoices(filters, additional_query_columns):
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
conditions = get_conditions(filters)
return frappe.db.sql("""select name, posting_date, debit_to, project, customer, customer_name, remarks,
base_net_total, base_grand_total, base_rounded_total, outstanding_amount
return frappe.db.sql("""select name, posting_date, debit_to, project, customer, customer_name, remarks,
base_net_total, base_grand_total, base_rounded_total, outstanding_amount {0}
from `tabSales Invoice`
where docstatus = 1 %s order by posting_date desc, name desc""" %
where docstatus = 1 %s order by posting_date desc, name desc""".format(additional_query_columns or '') %
conditions, filters, as_dict=1)
def get_invoice_income_map(invoice_list):
@@ -184,9 +206,8 @@ def get_invoice_so_dn_map(invoice_list):
return invoice_so_dn_map
def get_customer_details(invoice_list):
def get_customer_details(customers):
customer_map = {}
customers = list(set([inv.customer for inv in invoice_list]))
for cust in frappe.db.sql("""select name, territory, customer_group from `tabCustomer`
where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1):
customer_map.setdefault(cust.name, cust)

View File

@@ -311,6 +311,9 @@ def make_purchase_invoice(source_name, target_doc=None):
doc = get_mapped_doc("Purchase Order", source_name, {
"Purchase Order": {
"doctype": "Purchase Invoice",
"field_map": {
"party_account_currency": "party_account_currency"
},
"validation": {
"docstatus": ["=", 1],
}

View File

@@ -0,0 +1,3 @@
{% include "erpnext/regional/india/party.js" %}
erpnext.setup_gst_reminder_button('Supplier');

View File

@@ -1,3 +1,3 @@
frappe.listview_settings['Supplier'] = {
add_fields: ["supplier_name", "supplier_type"],
add_fields: ["supplier_name", "supplier_type", "image"],
};

View File

@@ -35,7 +35,7 @@ def get_data():
{
"type": "report",
"name": "Accounts Receivable",
"doctype": "Sales Invoice",
"doctype": "Sales Invoice",
"is_query_report": True
},
{
@@ -198,6 +198,39 @@ def get_data():
},
]
},
{
"label": _("Goods and Services Tax (GST India)"),
"items": [
{
"type": "doctype",
"name": "GST Settings",
},
{
"type": "doctype",
"name": "GST HSN Code",
},
{
"type": "report",
"name": "GST Sales Register",
"is_query_report": True
},
{
"type": "report",
"name": "GST Purchase Register",
"is_query_report": True
},
{
"type": "report",
"name": "GST Itemised Sales Register",
"is_query_report": True
},
{
"type": "report",
"name": "GST Itemised Purchase Register",
"is_query_report": True
},
]
},
{
"label": _("Budget and Cost Center"),
"items": [

View File

@@ -49,6 +49,12 @@ def get_data():
"doctype": "Issue",
"is_query_report": True
},
{
"type": "report",
"name": "Support Hours",
"doctype": "Issue",
"is_query_report": True
},
]
},
]

View File

@@ -255,7 +255,7 @@ class BuyingController(StockController):
def get_items_from_bom(self, item_code, bom):
bom_items = frappe.db.sql("""select t2.item_code,
t2.qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
t2.rate, t2.stock_uom, t2.name, t2.description
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
where t2.parent = t1.name and t1.item = %s

View File

@@ -316,6 +316,8 @@ def setup_account():
doc.parent_account = frappe.db.get_value('Account', {'account_name': doc.parent_account})
doc.insert()
frappe.flags.in_import = False
def setup_account_to_expense_type():
company_abbr = frappe.db.get_value("Company", erpnext.get_default_company(), "abbr")
expense_types = [{'name': _('Calls'), "account": "Sales Expenses - "+ company_abbr},
@@ -380,4 +382,6 @@ def import_json(doctype, submit=False, values=None):
frappe.db.commit()
frappe.flags.in_import = False

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -1,18 +1,17 @@
ERPNext Web Portal gives your customers quick access to their Orders, Invoices and Shipments Customers can check the status of their orders, invoices, and shipping status by logging on to the web.
Once an order is raised, either using the Shopping Cart or from within
ERPNext, your customer can view the order and keep an eye on the billing and
shipment status. When the invoice and payment against these orders are
submitted, the customer can see the updated status on the portal, at a glance.
<img class="screenshot" alt="Customer Portal" src="{{docs_base_url}}/assets/img/website/portal-menu.png">
<img class="screenshot" alt="Customer Portal" src={{docs_base_url}}/assets/img/website/place-order.png)
Once an order is raised, either using the Shopping Cart or from within ERPNext, your customer can view the order and keep an eye on the billing and shipment status. When the invoice and payment against these orders are submitted, the customer can see the updated status on the portal, at a glance.
<img class="screenshot" alt="Customer Portal" src="{{docs_base_url}}/assets/img/website/website-login.png">
#### Outstanding Sales Invoice
<img class="screenshot" alt="Customer Portal Order 1" src="{{docs_base_url}}/assets/img/website/invoice-unpaid.png">
<img class="screenshot" alt="Customer Portal" src="{{docs_base_url}}/assets/img/website/invoice-unpaid.png">
#### Paid Sales Invoice
<img class="screenshot" alt="Customer Portal Order 1" src="{{docs_base_url}}/assets/img/website/invoice-paid.png">
<img class="screenshot" alt="Customer Portal" src="{{docs_base_url}}/assets/img/website/invoice-paid.png">
{next}
{next}

View File

@@ -12,4 +12,5 @@ human-resources
customer-portal
website
using-erpnext
regional
customize-erpnext

View File

@@ -0,0 +1,9 @@
ERPNext aims to support local regulation for all the regions in the world. In most cases ERPNext is very flexible so you can easily add Custom Fields and make Custom Reports to support the regluation of your region.
As of mid-2017, ERPNext aims to pre-set additional fields and forms required for companies to easily submit reports to the relevant authorities.
This section is still under-development.
### Regions
{index}

View File

@@ -0,0 +1,21 @@
# Sending GST Reminders
You can send email reminders to your Customers and Suppliers so that they can directly add or update their GSTIN numbers
To send GSTIN Reminders, you can either open the Customer / Supplier record or **GST Settings**
<img class="screenshot" alt="GST Settings" src="{{docs_base_url}}/assets/img/regional/india/gst-settings.png">
Here you can click on the "Send GSTIN Update Reminders" button to send email reminders to all your customers
### Updating GSTIN
Your customers will receive an email asking them to update their GSTIN and that email will link them to a portal page:
<img class="screenshot" alt="GST Portal Page" src="{{docs_base_url}}/assets/img/regional/india/gstin-portal-update.png">
Here they can update their GSTIN and it will automatically be added to your customer GSTIN record.
#### Sample GSTIN Reminder Email
<img class="screenshot" alt="GST Reminder Email" src="{{docs_base_url}}/assets/img/regional/india/gstin-reminder-email.png">

View File

@@ -0,0 +1,67 @@
# GST Features in ERPNext
### 1. Setting up GSTIN
GST Law requires that you maintain the GSTIN number for all your suppliers and vendors. In ERPNext, GSTIN is linked to the **Address**
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gstin-customer.gif">
**GST for your Company Address**
You also need to set the Address for your own Company and your Company's GST Number
Go to the Company master and add the GSTIN to your default address.
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
### 2. Setting up HSN Codes
According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
<img class="screenshot" alt="HSN in Item" src="{{docs_base_url}}/assets/img/regional/india/hsn-item.gif">
### 3. Making Tax Masters
To setup Billing in GST, you need to create 3 Tax Accounts for the various GST reporting heads CGST - Central GST, SGST - State GST, IGST - Inter-state GST
Go to your **Chart of Accounts**, under the Duties and Taxes head of your account, create 3 Accounts
**Note:** Usually the rate in CGST and SGST is half of IGST. For example if most of your items are billed at 18%, then create IGST at 18%, CGST and SGST at 9% each.
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-in-coa.png">
### 4. Make Tax Templates
You will have have to make two tax templates for both your sales and purchase, one for in state sales and other for out of state sales.
In your **In State GST** template, select 2 accounts, SGST and CGST
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-template-in-state.png">
In your **Out of State GST** template, select IGST
### 5. Making GST Ready Invoices
If you have setup the GSTIN of your Customers and Suppliers, and your tax template, you are ready to go for making GST Ready Invoices!
For **Sales Invoice**,
1. Select the correct Customer and Item and the address where the transaction will happen.
2. Check if the GSTIN of your Company and Supplier have been correctly set.
3. Check if the HSN Number has been set in the Item
4. Select the the **In State GST** or **Out of State GST** template that you have created based on the type of transaction
5. Save and Submit the Invoice
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
### Reports
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
<img class="screenshot" alt="GST Menus" src="{{docs_base_url}}/assets/img/regional/india/gst-menu.png">
You can check the impact of your invoice in the **GST Sales Register** and **GST Itemised Sales Register**
<img class="screenshot" alt="GST Itemised Sales Register" src="{{docs_base_url}}/assets/img/regional/india/gst-itemised.png">

View File

@@ -0,0 +1,5 @@
# Statutory Requirements for India
As of 2017, India will fall under the new GST (Goods and Services Tax) regime and ERPNext makes it easy for users to track the details of its Supplier and Customers across Invoices and make the required reports.
{index}

View File

@@ -0,0 +1,2 @@
gst-setup
gst-reminders

View File

@@ -28,6 +28,9 @@ In ERPNext, you can select different type of Warehouses to stock your different
These numbers help to track individual units or batches of Items which you sell. It also tracks warranty and returns. In case any individual Item is recalled by the supplier the number system helps to track individual Item. The numbering system also manages expiry dates. Please note that if you sell your items in thousands, and if the items are very small like pens or erasers, you need not serialize them. In ERPNext, you will have to mention the serial number in some accounting entries. To create serial numbers you will have to manually create all the numbers in your entries. If your product is not a big consumer durable Item, if it has no warranty and has no chances of being recalled, avoid giving serial numbers.
> Tip: While entering an item code in an items table, if the table requires inventory details, then depending on whether the entered item is batched or serialized, you can enter serial or batch numbers right away in a pop-up dialog.
<img alt="Serial No modal" class="screenshot" src="{{docs_base_url}}/assets/img/stock/serial_no_modal.gif"><img alt="Batch No modal" class="screenshot" src="{{docs_base_url}}/assets/img/stock/batch_no_modal.png">
> Important: Once you mark an item as serialized or batched or neither, you cannot change it after you have made any stock entry.
* [Discussion on Serialized Inventory]({{docs_base_url}}/user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item.html)

View File

@@ -0,0 +1,8 @@
### Support Hours
This report provide the information about the time slot along with the count of issues has been reported during the slot daywise.
> Support > Reports > Support Hours
<img class="screenshot" alt="Maintenance Visit" src="{{docs_base_url}}/assets/img/support/support_hours.png">

View File

@@ -160,6 +160,9 @@ doc_events = {
},
"Payment Entry": {
"on_submit": "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"
},
'Address': {
'validate': 'erpnext.regional.india.utils.validate_gstin_for_india'
}
}

View File

@@ -5,7 +5,7 @@ frappe.provide("erpnext.bom");
frappe.ui.form.on("BOM", {
setup: function(frm) {
frm.add_fetch('buying_price_list', 'currency', 'currency')
frm.add_fetch('buying_price_list', 'currency', 'currency');
frm.fields_dict["items"].grid.get_field("bom_no").get_query = function(doc, cdt, cdn){
return {
filters: {'currency': frm.doc.currency}
@@ -74,6 +74,15 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
get_bom_material_detail(doc, cdt, cdn, scrap_items);
},
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
refresh_field("stock_qty", item.name, item.parentfield);
this.toggle_conversion_factor(item);
}
},
})
$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
@@ -300,6 +309,13 @@ frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) {
})
});
frappe.ui.form.on("BOM Item", "qty", function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
d.stock_qty = d.qty * d.conversion_factor;
refresh_field("items");
});
frappe.ui.form.on("BOM Operation", "operations_remove", function(frm) {
erpnext.bom.calculate_op_cost(frm.doc);
erpnext.bom.calculate_total(frm.doc);

View File

@@ -7,6 +7,7 @@ from frappe.utils import cint, cstr, flt
from frappe import _
from erpnext.setup.utils import get_exchange_rate
from frappe.website.website_generator import WebsiteGenerator
from erpnext.stock.get_item_details import get_conversion_factor
from operator import itemgetter
@@ -48,7 +49,7 @@ class BOM(WebsiteGenerator):
self.set_conversion_rate()
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", "qty", "BOM Item")
validate_uom_is_integer(self, "stock_uom", "stock_qty", "BOM Item")
self.validate_materials()
self.set_bom_material_details()
@@ -60,6 +61,7 @@ class BOM(WebsiteGenerator):
def on_update(self):
self.check_recursion()
self.update_stock_qty()
self.update_exploded_items()
def on_submit(self):
@@ -94,7 +96,7 @@ class BOM(WebsiteGenerator):
def set_bom_material_details(self):
for item in self.get("items"):
ret = self.get_bom_material_detail({"item_code": item.item_code, "item_name": item.item_name, "bom_no": item.bom_no,
"qty": item.qty})
"stock_qty": item.stock_qty})
for r in ret:
if not item.get(r):
item.set(r, ret[r])
@@ -122,8 +124,11 @@ class BOM(WebsiteGenerator):
'description' : item and args['description'] or '',
'image' : item and args['image'] or '',
'stock_uom' : item and args['stock_uom'] or '',
'uom' : item and args['stock_uom'] or '',
'conversion_factor' : 1,
'bom_no' : args['bom_no'],
'rate' : rate,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate if self.company_currency() == self.currency else rate * self.conversion_rate
}
return ret_item
@@ -160,7 +165,7 @@ class BOM(WebsiteGenerator):
for d in self.get("items"):
rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no,
'qty': d.qty})["rate"]
'stock_qty': d.stock_qty})["rate"]
if rate:
d.rate = rate
@@ -240,6 +245,19 @@ class BOM(WebsiteGenerator):
frappe.db.get_value('Price List', self.buying_price_list, 'currency') != self.currency:
frappe.throw(_("Currency of the price list {0} is not similar with the selected currency {1}").format(self.buying_price_list, self.currency))
def update_stock_qty(self):
for m in self.get('items'):
if not m.conversion_factor:
m.conversion_factor = flt(get_conversion_factor(m.item_code, m.uom)['conversion_factor'])
if m.uom and m.qty:
m.stock_qty = flt(m.conversion_factor)*flt(m.qty)
if not m.uom and m.stock_uom:
m.uom = m.stock_uom
m.qty = m.stock_qty
def set_conversion_rate(self):
self.conversion_rate = get_exchange_rate(self.currency, self.company_currency())
@@ -259,7 +277,7 @@ class BOM(WebsiteGenerator):
for m in self.get('items'):
if m.bom_no:
validate_bom_no(m.item_code, m.bom_no)
if flt(m.qty) <= 0:
if flt(m.stock_qty) <= 0:
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
@@ -351,9 +369,9 @@ class BOM(WebsiteGenerator):
d.rate = self.get_bom_unitcost(d.bom_no)
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
d.base_amount = d.amount * flt(self.conversion_rate)
d.qty_consumed_per_unit = flt(d.qty, self.precision("qty", d)) / flt(self.quantity, self.precision("quantity"))
d.qty_consumed_per_unit = flt(d.stock_qty, self.precision("stock_qty", d)) / flt(self.quantity, self.precision("quantity"))
total_rm_cost += d.amount
base_total_rm_cost += d.base_amount
@@ -367,7 +385,7 @@ class BOM(WebsiteGenerator):
for d in self.get('scrap_items'):
d.base_rate = d.rate * self.conversion_rate
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
d.base_amount = d.amount * self.conversion_rate
total_sm_cost += d.amount
base_total_sm_cost += d.base_amount
@@ -385,7 +403,7 @@ class BOM(WebsiteGenerator):
self.cur_exploded_items = {}
for d in self.get('items'):
if d.bom_no:
self.get_child_exploded_items(d.bom_no, d.qty)
self.get_child_exploded_items(d.bom_no, d.stock_qty)
else:
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d.item_code,
@@ -393,7 +411,7 @@ class BOM(WebsiteGenerator):
'description' : d.description,
'image' : d.image,
'stock_uom' : d.stock_uom,
'qty' : flt(d.qty),
'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate,
}))
@@ -402,16 +420,16 @@ class BOM(WebsiteGenerator):
def add_to_cur_exploded_items(self, args):
if self.cur_exploded_items.get(args.item_code):
self.cur_exploded_items[args.item_code]["qty"] += args.qty
self.cur_exploded_items[args.item_code]["stock_qty"] += args.stock_qty
else:
self.cur_exploded_items[args.item_code] = args
def get_child_exploded_items(self, bom_no, qty):
def get_child_exploded_items(self, bom_no, stock_qty):
""" Add all items from Flat BOM of child BOM"""
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name, bom_item.description,
bom_item.stock_uom, bom_item.qty, bom_item.rate,
bom_item.qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
bom_item.stock_uom, bom_item.stock_qty, bom_item.rate,
bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
from `tabBOM Explosion Item` bom_item, tabBOM bom
where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
@@ -421,7 +439,7 @@ class BOM(WebsiteGenerator):
'item_name' : d['item_name'],
'description' : d['description'],
'stock_uom' : d['stock_uom'],
'qty' : d['qty_consumed_per_unit']*qty,
'stock_qty' : d['qty_consumed_per_unit']*stock_qty,
'rate' : flt(d['rate']),
}))
@@ -433,8 +451,8 @@ class BOM(WebsiteGenerator):
ch = self.append('exploded_items', {})
for i in self.cur_exploded_items[d].keys():
ch.set(i, self.cur_exploded_items[d][i])
ch.amount = flt(ch.qty) * flt(ch.rate)
ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.quantity)
ch.amount = flt(ch.stock_qty) * flt(ch.rate)
ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
ch.docstatus = self.docstatus
ch.db_insert()
@@ -468,7 +486,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
query = """select
bom_item.item_code,
item.item_name,
sum(bom_item.qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
item.description,
item.image,
item.stock_uom,
@@ -478,13 +496,13 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
from
`tab{table}` bom_item, `tabBOM` bom, `tabItem` item
where
bom_item.parent = bom.name
and bom_item.docstatus < 2
and bom_item.parent = %(bom)s
bom_item.docstatus < 2
and bom.name = %(bom)s
and bom_item.parent = bom.name
and item.name = bom_item.item_code
and is_stock_item = 1
{conditions}
group by item_code, stock_uom"""
group by item_code, stock_uom"""
if fetch_exploded:
query = query.format(table="BOM Explosion Item",
@@ -536,7 +554,7 @@ def get_children():
return frappe.db.sql("""select
bom_item.item_code,
bom_item.bom_no as value,
bom_item.qty,
bom_item.stock_qty,
if(ifnull(bom_item.bom_no, "")!="", 1, 0) as expandable,
item.image,
item.description

View File

@@ -6,7 +6,7 @@
"doctype": "BOM Item",
"item_code": "_Test Serialized Item With Series",
"parentfield": "items",
"qty": 1.0,
"stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -15,7 +15,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item 2",
"parentfield": "items",
"qty": 2.0,
"stock_qty": 2.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -35,7 +35,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "items",
"qty": 1.0,
"stock_qty": 1.0,
"rate": 2000.0,
"stock_uom": "_Test UOM"
}
@@ -46,7 +46,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
"qty": 1.0,
"stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -55,7 +55,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "items",
"qty": 2.0,
"stock_qty": 2.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -84,7 +84,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
"qty": 1.0,
"stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -94,7 +94,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop Manufactured",
"parentfield": "items",
"qty": 3.0,
"stock_qty": 3.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -124,7 +124,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
"qty": 2.0,
"stock_qty": 2.0,
"rate": 3000.0,
"stock_uom": "_Test UOM"
}

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -44,6 +46,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +75,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -101,6 +105,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -129,6 +134,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -161,6 +167,7 @@
"width": "300px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -189,6 +196,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -218,6 +226,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -248,6 +257,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -276,11 +286,12 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "qty",
"fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -289,7 +300,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Qty",
"label": "Stock Qty",
"length": 0,
"no_copy": 0,
"oldfieldname": "qty",
@@ -306,6 +317,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -337,6 +349,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -365,6 +378,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -393,6 +407,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -424,6 +439,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -455,17 +471,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-17 17:27:43.757983",
"modified": "2017-06-02 19:29:34.498719",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Explosion Item",

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -20,7 +22,8 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
@@ -41,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -51,6 +55,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Name",
@@ -69,6 +74,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -79,6 +85,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
@@ -96,6 +103,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -105,7 +113,8 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM No",
@@ -128,6 +137,7 @@
"width": "150px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -138,6 +148,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
@@ -155,6 +166,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -165,6 +177,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Description",
@@ -186,6 +199,7 @@
"width": "250px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -196,6 +210,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
@@ -212,6 +227,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -222,6 +238,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image",
@@ -240,6 +257,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -250,6 +268,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image View",
@@ -269,6 +288,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -279,6 +299,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity and Rate",
@@ -296,6 +317,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -306,6 +328,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Qty",
@@ -319,16 +342,170 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 1,
"fieldname": "uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "UOM",
"length": 0,
"no_copy": 0,
"options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock Qty",
"length": 0,
"no_copy": 0,
"oldfieldname": "stock_qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"columns": 0,
"fieldname": "conversion_factor",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Conversion Factor",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock UOM",
"length": 0,
"no_copy": 0,
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"options": "UOM",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "See \"Rate Of Materials Based On\" in Costing Section",
"fieldname": "rate",
"fieldtype": "Currency",
@@ -336,7 +513,8 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate",
"length": 0,
@@ -354,6 +532,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -364,6 +543,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Amount",
@@ -386,62 +566,7 @@
"width": "150px"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock UOM",
"length": 0,
"no_copy": 0,
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"options": "UOM",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -452,6 +577,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Basic Rate (Company Currency)",
@@ -471,6 +597,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -481,6 +608,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amount (Company Currency)",
@@ -500,6 +628,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -510,6 +639,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
@@ -527,6 +657,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -537,6 +668,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Scrap %",
@@ -556,6 +688,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -566,6 +699,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Qty Consumed Per Unit",
@@ -585,18 +719,18 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-12-20 12:54:34.859076",
"modified_by": "rmehta@gmail.com",
"modified": "2017-05-23 15:59:37.946963",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
"owner": "Administrator",
@@ -604,7 +738,9 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -33,7 +33,7 @@ class BOMReplaceTool(Document):
from `tabBOM` where name = %s""", self.current_bom)
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2""",
(self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom))
def get_parent_boms(self):

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -21,7 +23,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
@@ -31,6 +35,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -38,6 +43,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -48,7 +54,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
@@ -57,6 +65,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -64,6 +73,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,7 +84,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity and Rate",
"length": 0,
"no_copy": 0,
@@ -83,6 +95,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -90,17 +103,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "qty",
"fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Qty",
"length": 0,
"no_copy": 0,
@@ -109,6 +125,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -116,6 +133,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -126,7 +144,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Rate",
"length": 0,
"no_copy": 0,
@@ -136,6 +156,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -143,6 +164,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -153,7 +175,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
@@ -163,6 +187,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -170,6 +195,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -180,7 +206,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -188,6 +216,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -195,6 +224,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -205,7 +235,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock UOM",
"length": 0,
"no_copy": 0,
@@ -215,6 +247,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -222,6 +255,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -232,7 +266,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Basic Rate (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -242,6 +278,7 @@
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -249,6 +286,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -259,7 +297,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Basic Amount (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -269,6 +309,7 @@
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -276,17 +317,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-10-25 00:27:53.712140",
"modified": "2017-05-23 16:04:32.442287",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Scrap Item",
@@ -296,7 +337,9 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -266,9 +266,9 @@ class TestProductionOrder(unittest.TestCase):
def get_scrap_item_details(bom_no):
scrap_items = {}
for item in frappe.db.sql("""select item_code, qty from `tabBOM Scrap Item`
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
where parent = %s""", bom_no, as_dict=1):
scrap_items[item.item_code] = item.qty
scrap_items[item.item_code] = item.stock_qty
return scrap_items
@@ -287,8 +287,7 @@ def make_prod_order_test_record(**args):
pro_order.stock_uom = args.stock_uom or "_Test UOM"
pro_order.use_multi_level_bom=0
pro_order.set_production_order_operations()
if args.source_warehouse:
pro_order.source_warehouse = args.source_warehouse
@@ -297,6 +296,7 @@ def make_prod_order_test_record(**args):
if not args.do_not_save:
pro_order.insert()
if not args.do_not_submit:
pro_order.submit()
return pro_order

View File

@@ -321,7 +321,7 @@ class ProductionPlanningTool(Document):
# get all raw materials with sub assembly childs
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
for d in frappe.db.sql("""select fb.item_code,
ifnull(sum(fb.qty/ifnull(bom.quantity, 1)), 0) as qty,
ifnull(sum(fb.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
fb.description, fb.stock_uom, item.min_order_qty
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` item
where bom.name = fb.parent and item.name = fb.item_code
@@ -348,7 +348,7 @@ class ProductionPlanningTool(Document):
SELECT
bom_item.item_code,
default_material_request_type,
ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
item.is_sub_contracted_item as is_sub_contracted,
item.default_bom as default_bom,
bom_item.description as description,

View File

@@ -235,9 +235,9 @@ def create_test_records():
"is_active": 1,
"is_default": 1,
"docstatus": 1,
"with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "qty":1,
"with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "stock_qty":1,
"rate":100, "amount": 100, "stock_uom": "_Test UOM"},
{"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "qty":4, "rate":100,
{"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "stock_qty":4, "rate":100,
"amount": 400,"stock_uom": "_Test UOM"}])
bom_subC = make_bom("BOM-_Test PPT Item Sub C-001",{"quantity":1,
@@ -247,9 +247,9 @@ def create_test_records():
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
"doctype":"BOM Item", "qty":6, "rate":100, "amount": 600},
"doctype":"BOM Item", "stock_qty":6, "rate":100, "amount": 600},
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
"bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "qty":2,
"bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "stock_qty":2,
"rate":100, "amount": 200}])
bom_sCA = make_bom("BOM-_Test PPT Item SC A-001",{"quantity":1,
@@ -259,7 +259,7 @@ def create_test_records():
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw D","item_name": "_Test PPT Item Raw D",
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}])
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}])
bom_sCB = make_bom("BOM-_Test PPT Item SC B-001",{"quantity":1,
"item": "_Test PPT Item SC B",
@@ -268,9 +268,9 @@ def create_test_records():
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw B","item_name": "_Test PPT Item Raw B",
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item Raw C","item_name": "_Test PPT Item Raw C",
"doctype":"BOM Item", "qty":4, "rate":100, "amount": 400}])
"doctype":"BOM Item", "stock_qty":4, "rate":100, "amount": 400}])
bom_subA = make_bom("BOM-_Test PPT Item Sub A-001",{"quantity":1,
"item": "_Test PPT Item Sub A",
@@ -278,11 +278,11 @@ def create_test_records():
"is_default": 1,
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
{"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
"bom_no":"BOM-_Test PPT Item Sub C-001", "doctype":"BOM Item",
"qty":1, "rate":100, "amount": 100},
"stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item SC B","item_name": "_Test PPT Item SC B",
"bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "qty":2,
"bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "stock_qty":2,
"rate":100, "amount": 200}])
bom_master = make_bom("BOM-_Test PPT Item Master-001",{"quantity":1,
@@ -293,16 +293,16 @@ def create_test_records():
"with_operations": 0}, [
{"item_code": "_Test PPT Item Sub A","item_name": "_Test PPT Item Sub A",
"bom_no":"BOM-_Test PPT Item Sub A-001",
"doctype":"BOM Item", "qty":2, "rate":100, "amount": 200},
"doctype":"BOM Item", "stock_qty":2, "rate":100, "amount": 200},
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
"bom_no":"BOM-_Test PPT Item Sub B-001",
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
"doctype":"BOM Item", "qty":2, "rate":100,
"doctype":"BOM Item", "stock_qty":2, "rate":100,
"amount": 200},
{"item_code": "_Test PPT Item SC A","item_name": "_Test PPT Item SC A",
"bom_no":"BOM-_Test PPT Item SC A-001",
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}
])
@@ -388,4 +388,4 @@ def get_requested_types(item_code):
where item.item_code = %(item_code)s and item.parent = mat_req.name""", {"item_code":item_code}, as_dict=1):
types.append(d.type)
return types

View File

@@ -23,7 +23,7 @@ def get_item_list(prod_list, filters):
item_list = frappe.db.sql("""SELECT
bom_item.item_code as item_code,
ifnull(ledger.actual_qty*bom.quantity/bom_item.qty,0) as build_qty
ifnull(ledger.actual_qty*bom.quantity/bom_item.stock_qty,0) as build_qty
FROM
`tabBOM` as bom, `tabBOM Item` AS bom_item
LEFT JOIN `tabBin` AS ledger

View File

@@ -13,4 +13,5 @@ Shopping Cart
Hub Node
Portal
Maintenance
Schools
Schools
Regional

View File

@@ -403,7 +403,10 @@ erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
erpnext.patches.v8_0.delete_bin_indexes
erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory
erpnext.patches.v8_0.change_in_words_varchar_length
erpnext.patches.v8_0.update_stock_qty_value_in_bom_item
erpnext.patches.v8_0.create_domain_docs #16-05-2017
erpnext.patches.v8_0.update_sales_cost_in_project
erpnext.patches.v8_0.save_system_settings
erpnext.patches.v8_1.delete_deprecated_reports
erpnext.patches.v8_1.delete_deprecated_reports
erpnext.patches.v8_1.setup_gst_india #2017-06-27
execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')

View File

@@ -4,8 +4,8 @@ from frappe.utils import update_progress_bar
def execute():
frappe.reload_doc('core', 'doctype', 'dynamic_link')
frappe.reload_doc('email', 'doctype', 'contact')
frappe.reload_doc('contact', 'doctype', 'address')
frappe.reload_doc('contacts', 'doctype', 'contact')
frappe.reload_doc('contacts', 'doctype', 'address')
map_fields = (
('Customer', 'customer'),
('Supplier', 'supplier'),

View File

@@ -21,7 +21,7 @@ def execute():
condition = ""
company = erpnext.get_default_company()
if company:
condition = " and name='{0}'".format(company)
condition = " and name='{0}'".format(frappe.db.escape(company))
domains = frappe.db.sql_list("select distinct domain from `tabCompany` where domain != 'Other' {0}".format(condition))

View File

@@ -10,4 +10,4 @@ def execute():
for data in frappe.get_all('Company', fields = ["name"]):
doc = frappe.get_doc('Company', data.name)
doc.enable_perpetual_inventory = enabled
doc.save(ignore_permissions=True)
doc.db_update()

View File

@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint
def execute():
"""
@@ -10,6 +11,10 @@ def execute():
"""
frappe.reload_doc("core", "doctype", "system_settings")
doc = frappe.get_doc("System Settings", "System Settings")
doc = frappe.get_doc("System Settings")
doc.flags.ignore_mandatory = True
if cint(doc.currency_precision) == 0:
doc.currency_precision = ''
doc.save(ignore_permissions=True)

View File

@@ -0,0 +1,13 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('manufacturing', 'doctype', 'bom_item')
frappe.reload_doc('manufacturing', 'doctype', 'bom_explosion_item')
frappe.reload_doc('manufacturing', 'doctype', 'bom_scrap_item')
frappe.db.sql("update `tabBOM Item` set stock_qty = qty, uom = stock_uom, conversion_factor = 1")
frappe.db.sql("update `tabBOM Explosion Item` set stock_qty = qty")
frappe.db.sql("update `tabBOM Scrap Item` set stock_qty = qty")

View File

@@ -7,9 +7,48 @@ import frappe
def execute():
""" delete deprecated reports """
reports = ["Monthly Salary Register", "Customer Addresses And Contacts",
"Supplier Addresses And Contacts"]
reports = [
"Monthly Salary Register", "Customer Addresses And Contacts",
"Supplier Addresses And Contacts"
]
for report in reports:
if frappe.db.exists("Report", report):
frappe.delete_doc("Report", report, ignore_permissions=True)
check_and_update_desktop_icon_for_report(report)
check_and_update_auto_email_report(report)
frappe.db.commit()
frappe.delete_doc("Report", report, ignore_permissions=True)
def check_and_update_desktop_icon_for_report(report):
""" delete or update desktop icon"""
desktop_icons = frappe.db.sql_list("""select name from `tabDesktop Icon`
where _report='{0}'""".format(report))
if not desktop_icons:
return
if report == "Monthly Salary Register":
for icon in desktop_icons:
frappe.delete_doc("Desktop Icon", icon)
elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]:
frappe.db.sql("""update `tabDesktop Icon` set _report='{value}'
where name in ({docnames})""".format(
value="Addresses And Contacts",
docnames=",".join(["'%s'"%icon for icon in desktop_icons])
)
)
def check_and_update_auto_email_report(report):
""" delete or update auto email report for deprecated report """
auto_email_report = frappe.db.get_value("Auto Email Report", {"report": report})
if not auto_email_report:
return
if report == "Monthly Salary Register":
frappe.delete_doc("Auto Email Report", auto_email_report)
elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]:
frapppe.db.set_value("Auto Email Report", auto_email_report, "report", report)

View File

@@ -0,0 +1,45 @@
import frappe
from frappe.email import sendmail_to_system_managers
def execute():
frappe.reload_doc('regional', 'doctype', 'gst_settings')
frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
frappe.reload_doc('stock', 'doctype', 'item')
for report_name in ('GST Sales Register', 'GST Purchase Register',
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
frappe.reload_doc('regional', 'report', frappe.scrub(report_name))
if frappe.db.get_single_value('System Settings', 'country')=='India':
from erpnext.regional.india.setup import setup
delete_custom_field_tax_id_if_exists()
setup(patch=True)
send_gst_update_email()
def delete_custom_field_tax_id_if_exists():
for field in frappe.db.sql_list("""select name from `tabCustom Field` where fieldname='tax_id'
and dt in ('Sales Order', 'Sales Invoice', 'Delivery Note')"""):
frappe.delete_doc("Custom Field", field, ignore_permissions=True)
frappe.db.commit()
def send_gst_update_email():
message = """Hello,
<p>ERPNext is now GST Ready!</p>
<p>To start making GST Invoices from 1st of July, you just need to create new Tax Accounts,
Templates and update your Customer's and Supplier's GST Numbers.</p>
<p>Please refer {gst_document_link} to know more about how to setup and implement GST in ERPNext.</p>
<p>Please contact us at support@erpnext.com, if you have any questions.</p>
<p>Thanks,</p>
ERPNext Team.
""".format(gst_document_link="<a href='http://frappe.github.io/erpnext/user/manual/en/regional/india/'> ERPNext GST Document </a>")
try:
sendmail_to_system_managers("[Important] ERPNext GST updates", message)
except Exception as e:
pass

View File

@@ -104,7 +104,7 @@ body[data-route="pos"] .pos-payment-row {
}
body[data-route="pos"] .pos-payment-row:hover,
body[data-route="pos"] .pos-keyboard-key:hover {
background-color: #FAFBFC;
background-color: #fafbfc;
cursor: pointer;
}
body[data-route="pos"] .pos-keyboard-key,
@@ -214,7 +214,7 @@ body[data-route="pos"] .amount-label {
font-size: 16px;
}
body[data-route="pos"] .selected-payment-mode {
background-color: #FAFBFC;
background-color: #fafbfc;
cursor: pointer;
}
body[data-route="pos"] .pos-invoice-list {

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -265,6 +265,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
item_code: function(doc, cdt, cdn, from_barcode) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
var update_stock = 0, show_batch_dialog = 0;
if(['Sales Invoice', 'Purchase Invoice'].includes(this.frm.doc.doctype)) {
update_stock = cint(me.frm.doc.update_stock);
show_batch_dialog = update_stock;
} else if((this.frm.doc.doctype === 'Purchase Receipt' && me.frm.doc.is_return) ||
this.frm.doc.doctype === 'Delivery Note') {
show_batch_dialog = 1;
}
// clear barcode if setting item (else barcode will take priority)
if(!from_barcode) {
@@ -272,7 +282,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
if(item.item_code || item.barcode || item.serial_no) {
if(!this.validate_company_and_party()) {
cur_frm.fields_dict["items"].grid.grid_rows[item.idx - 1].remove();
this.frm.fields_dict["items"].grid.grid_rows[item.idx - 1].remove();
} else {
return this.frm.call({
method: "erpnext.stock.get_item_details.get_item_details",
@@ -286,7 +296,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
customer: me.frm.doc.customer,
supplier: me.frm.doc.supplier,
currency: me.frm.doc.currency,
update_stock: in_list(['Sales Invoice', 'Purchase Invoice'], me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0,
update_stock: update_stock,
conversion_rate: me.frm.doc.conversion_rate,
price_list: me.frm.doc.selling_price_list || me.frm.doc.buying_price_list,
price_list_currency: me.frm.doc.price_list_currency,
@@ -310,6 +320,13 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(!r.exc) {
me.frm.script_manager.trigger("price_list_rate", cdt, cdn);
me.toggle_conversion_factor(item);
if(show_batch_dialog) {
var d = locals[cdt][cdn];
$.each(r.message, function(k, v) {
if(!d[k]) d[k] = v;
});
erpnext.show_serial_batch_selector(me.frm, d);
}
}
}
});
@@ -1166,3 +1183,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
},
});
erpnext.show_serial_batch_selector = function(frm, d) {
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {
new erpnext.SerialNoBatchSelector({
frm: frm,
item: d,
warehouse_details: {
type: "Warehouse",
name: d.warehouse
},
});
});
}

View File

@@ -51,20 +51,28 @@ $.extend(erpnext.queries, {
return {
query: 'frappe.contacts.doctype.contact.contact.contact_query',
filters: { link_doctype: frappe.dynamic_link.doctype, link_name: doc[frappe.dynamic_link.fieldname] } };
filters: {
link_doctype: frappe.dynamic_link.doctype,
link_name: doc[frappe.dynamic_link.fieldname]
}
};
}
},
address_query: function(doc) {
if(frappe.dynamic_link) {
if(!doc[frappe.dynamic_link.fieldname]) {
frappe.throw(__("Please set {0}",
frappe.throw(__("Please set {0}",
[__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))]));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: { link_doctype: frappe.dynamic_link.doctype, link_name: doc[frappe.dynamic_link.fieldname] } };
filters: {
link_doctype: frappe.dynamic_link.doctype,
link_name: doc[frappe.dynamic_link.fieldname]
}
};
}
},
@@ -85,7 +93,7 @@ $.extend(erpnext.queries, {
lead_filter: function(doc) {
if(!doc.lead) {
frappe.throw(__("Please specify a {0}",
frappe.throw(__("Please specify a {0}",
[__(frappe.meta.get_label(doc.doctype, "lead", doc.name))]));
}

View File

@@ -1,6 +1,6 @@
<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
<div class="clearfix"></div>
{% for(var i=0, l=addr_list.length; i<l; i++) { %}
<div class="address-box">
<p class="h6">
{%= i+1 %}. {%= addr_list[i].address_type!="Other" ? __(addr_list[i].address_type) : addr_list[i].address_title %}
{% if(addr_list[i].is_primary_address) { %}
@@ -9,14 +9,15 @@
<span class="text-muted">({%= __("Shipping") %})</span>{% } %}
<a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}"
class="btn btn-default btn-xs pull-right">
class="btn btn-default btn-xs pull-right"
style="margin-top:-3px; margin-right: -5px;">
{%= __("Edit") %}</a>
</p>
<div style="padding-left: 15px;">
<p style="margin-top: 5px; font-size: 12px;">
{%= addr_list[i].display %}</p>
</p>
<p>{%= addr_list[i].display %}</p>
</div>
{% } %}
{% if(!addr_list.length) { %}
<p class="text-muted">{%= __("No address added yet.") %}</p>
<p class="text-muted small">{%= __("No address added yet.") %}</p>
{% } %}
<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>

View File

@@ -1,38 +1,38 @@
<p><button class="btn btn-xs btn-default btn-contact">
{{ __("New Contact") }}</button></p>
<div class="clearfix"></div>
<ol>
<div class="clearfix"></div>
{% for(var i=0, l=contact_list.length; i<l; i++) { %}
<p class="h6">
<li>
{%= contact_list[i].first_name %} {%= contact_list[i].last_name %}
{% if(contact_list[i].is_primary_contact) { %}
<span class="text-muted">({%= __("Primary") %})</span>
{% } %}
{% if(contact_list[i].designation){ %}
<span class="text-muted">&ndash; {%= contact_list[i].designation %}</span>
{% } %}
<a href="#Form/Contact/{%= encodeURIComponent(contact_list[i].name) %}"
class="btn btn-xs btn-default pull-right">
{%= __("Edit") %}</a>
</li>
</p>
<div style="padding-left: 15px;">
<p style="padding-top: 5px; font-size: 12px;">
{% if(contact_list[i].phone) { %}
{%= __("Phone") %}: {%= contact_list[i].phone %}<br>
{% } %}
{% if(contact_list[i].mobile_no) { %}
{%= __("Mobile No.") %}: {%= contact_list[i].mobile_no %}<br>
{% } %}
{% if(contact_list[i].email_id) { %}
{%= __("Email Address") %}: {%= contact_list[i].email_id %}
{% } %}
</p>
</div>
<div class="address-box">
<p class="h6">
{%= contact_list[i].first_name %} {%= contact_list[i].last_name %}
{% if(contact_list[i].is_primary_contact) { %}
<span class="text-muted">({%= __("Primary") %})</span>
{% } %}
{% if(contact_list[i].designation){ %}
<span class="text-muted">&ndash; {%= contact_list[i].designation %}</span>
{% } %}
<a href="#Form/Contact/{%= encodeURIComponent(contact_list[i].name) %}"
class="btn btn-xs btn-default pull-right"
style="margin-top:-3px; margin-right: -5px;">
{%= __("Edit") %}</a>
</p>
{% if (contact_list[i].phone || contact_list[i].mobile_no ||
contact_list[i].email_id) { %}
<p>
{% if(contact_list[i].phone) { %}
{%= __("Phone") %}: {%= contact_list[i].phone %}<br>
{% } %}
{% if(contact_list[i].mobile_no) { %}
{%= __("Mobile No.") %}: {%= contact_list[i].mobile_no %}<br>
{% } %}
{% if(contact_list[i].email_id) { %}
{%= __("Email Address") %}: {%= contact_list[i].email_id %}
{% } %}
</p>
{% endif %}
</div>
{% } %}
</ol>
{% if(!contact_list.length) { %}
<p class="text-muted">{%= __("No contacts added yet.") %}</p>
{% } %}
<p class="text-muted small">{%= __("No contacts added yet.") %}</p>
{% } %}
<p><button class="btn btn-xs btn-default btn-contact">
{{ __("New Contact") }}</button>
</p>

View File

@@ -0,0 +1,327 @@
erpnext.SerialNoBatchSelector = Class.extend({
init: function(opts) {
$.extend(this, opts);
// frm, item, warehouse_details, has_batch, oldest
let d = this.item;
// Don't show dialog if batch no or serial no already set
if(d && d.has_batch_no && !d.batch_no) {
this.has_batch = 1;
this.setup();
} else if(d && d.has_serial_no && !d.serial_no) {
this.has_batch = 0;
this.setup();
}
},
setup: function() {
this.item_code = this.item.item_code;
this.qty = this.item.qty;
this.make_dialog();
},
make_dialog: function() {
var me = this;
this.data = this.oldest ? this.oldest : [];
let title = "";
let fields = [
{
fieldname: 'item_code',
read_only: 1,
fieldtype:'Link',
options: 'Item',
label: __('Item Code'),
default: me.item_code
},
{fieldtype:'Column Break'},
{
fieldname: 'warehouse',
fieldtype:'Link',
options: 'Warehouse',
label: __(me.warehouse_details.type),
default: me.warehouse_details.name,
onchange: function(e) {
me.warehouse_details.name = this.get_value();
var batches = this.layout.fields_dict.batches;
if(batches) {
batches.grid.df.data = [];
batches.grid.refresh();
batches.grid.add_new_row(null, null, null);
}
}
},
{fieldtype:'Column Break'},
{
fieldname: 'qty',
fieldtype:'Float',
read_only: 1,
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
default: me.qty
},
];
if(this.has_batch) {
title = __("Select Batch Numbers");
fields = fields.concat(this.get_batch_fields());
} else {
title = __("Select Serial Numbers");
fields = fields.concat(this.get_serial_no_fields());
}
this.dialog = new frappe.ui.Dialog({
title: title,
fields: fields
});
this.bind_qty();
this.dialog.set_primary_action(__('Insert'), function() {
me.values = me.dialog.get_values();
if(me.validate()) {
me.set_items();
me.dialog.hide();
}
});
this.dialog.show();
},
validate: function() {
let values = this.values;
if(!values.warehouse) {
frappe.throw(__("Please select a warehouse"));
return false;
}
if(this.has_batch) {
if(values.batches.length === 0 || !values.batches) {
frappe.throw(__("Please select batches for batched item "
+ values.item_code));
return false;
}
values.batches.map((batch, i) => {
if(!batch.selected_qty || batch.selected_qty === 0 ) {
frappe.throw(__("Please select quantity on row " + (i+1)));
return false;
}
});
return true;
} else {
let serial_nos = values.serial_no || '';
if (!serial_nos || !serial_nos.replace(/\s/g, '').length) {
frappe.throw(__("Please enter serial numbers for serialized item "
+ values.item_code));
return false;
}
return true;
}
},
set_items: function() {
var me = this;
if(this.has_batch) {
this.values.batches.map((batch, i) => {
let item_code_field = {};
let row = (i !== 0) ? this.frm.add_child("items", this.item) : this.item;
this.map_row_values(row, batch, 'batch_no',
'selected_qty', this.values.warehouse);
});
} else {
this.map_row_values(this.item, this.values, 'serial_no', 'qty');
}
refresh_field("items");
},
map_row_values: function(row, values, number, qty_field, warehouse) {
row.qty = values[qty_field];
row[number] = values[number];
if(this.warehouse_details.type === 'Source Warehouse') {
row.s_warehouse = values.warehouse || warehouse;
} else if(this.warehouse_details.type === 'Target Warehouse') {
row.t_warehouse = values.warehouse || warehouse;
} else {
row.warehouse = values.warehouse || warehouse;
}
},
bind_qty: function() {
let serial_no_link = this.dialog.fields_dict.serial_no_select;
let serial_no_list_field = this.dialog.fields_dict.serial_no;
let batches_field = this.dialog.fields_dict.batches;
let qty_field = this.dialog.fields_dict.qty;
let update_quantity = (batch) => {
if(batch) {
let total_qty = 0;
batches_field.grid.wrapper.find(
'input[data-fieldname="selected_qty"]').each(function() {
total_qty += Number($(this).val());
});
qty_field.set_input(total_qty);
} else {
let serial_numbers = serial_no_list_field.get_value()
.replace(/\n/g, ' ').match(/\S+/g) || [];
qty_field.set_input(serial_numbers.length);
}
};
if(serial_no_link) {
let serial_list = [];
serial_no_link.$input.on('awesomplete-selectcomplete', function() {
if(serial_no_link.get_value().length > 0) {
let new_no = serial_no_link.get_value();
let list_value = serial_no_list_field.get_value();
let new_line = '\n';
if(!serial_no_list_field.get_value()) {
new_line = '';
} else {
serial_list = list_value.replace(/\s+/g, ' ').split(' ');
}
if(!serial_list.includes(new_no)) {
serial_no_link.set_new_description('');
serial_no_list_field.set_value(list_value + new_line + new_no);
update_quantity(0);
} else {
serial_no_link.set_new_description(new_no + ' is already selected.');
}
}
// Should, but doesn't work
serial_no_link.set_input('');
serial_no_link.$input.blur();
});
serial_no_list_field.$input.on('input', function() {
serial_list = serial_no_list_field.get_value().replace(/\s+/g, ' ').split(' ');
update_quantity(0);
});
}
if(batches_field) {
batches_field.grid.wrapper.on('change', function() {
update_quantity(1);
});
}
},
get_batch_fields: function() {
var me = this;
return [
{fieldtype:'Section Break', label: __('Batches')},
{fieldname: 'batches', fieldtype: 'Table',
fields: [
{
fieldtype:'Link',
fieldname:'batch_no',
options: 'Batch',
label: __('Select Batch'),
in_list_view:1,
get_query: function() {
return {filters: {item: me.item_code }};
},
onchange: function(e) {
let val = this.get_value();
if(val.length === 0) {
this.grid_row.on_grid_fields_dict
.available_qty.set_value(0);
return;
}
let selected_batches = this.grid.grid_rows.map((row) => {
if(row === this.grid_row) {
return "";
}
return row.on_grid_fields_dict.batch_no.get_value();
});
if(selected_batches.includes(val)) {
this.set_value("");
frappe.throw(__(`Batch ${val} already selected.`));
return;
}
if(me.warehouse_details.name) {
frappe.call({
method: 'erpnext.stock.doctype.batch.batch.get_batch_qty',
args: {
batch_no: this.doc.batch_no,
warehouse: me.warehouse_details.name,
item_code: me.item_code
},
callback: (r) => {
this.grid_row.on_grid_fields_dict
.available_qty.set_value(r.message || 0);
}
});
} else {
this.set_value("");
frappe.throw(__(`Please select a warehouse to get available
quantities`));
}
// e.stopImmediatePropagation();
}
},
{
fieldtype:'Float',
read_only:1,
fieldname:'available_qty',
label: __('Available'),
in_list_view:1,
default: 0,
onchange: function() {
this.grid_row.on_grid_fields_dict.selected_qty.set_value('0');
}
},
{
fieldtype:'Float',
fieldname:'selected_qty',
label: __('Qty'),
in_list_view:1,
'default': 0,
onchange: function(e) {
var batch_no = this.grid_row.on_grid_fields_dict.batch_no.get_value();
var available_qty = this.grid_row.on_grid_fields_dict.available_qty.get_value();
var selected_qty = this.grid_row.on_grid_fields_dict.selected_qty.get_value();
if(batch_no.length === 0 && parseInt(selected_qty)!==0) {
frappe.throw(__("Please select a batch"));
}
if(me.warehouse_details.type === 'Source Warehouse' &&
parseFloat(available_qty) < parseFloat(selected_qty)) {
this.set_value('0');
frappe.throw(__(`For transfer from source, selected quantity cannot be
greater than available quantity`));
} else {
this.grid.refresh();
}
}
},
],
in_place_edit: true,
data: this.data,
get_data: function() {
return this.data;
},
}
];
},
get_serial_no_fields: function() {
var me = this;
return [
{fieldtype: 'Section Break', label: __('Serial No')},
{
fieldtype: 'Link', fieldname: 'serial_no_select', options: 'Serial No',
label: __('Select'),
get_query: function() {
return { filters: {item_code: me.item_code}};
}
},
{fieldtype: 'Column Break'},
{fieldname: 'serial_no', fieldtype: 'Small Text'}
];
}
});

View File

@@ -126,7 +126,7 @@ body[data-route="pos"] {
}
.pos-payment-row {
border-bottom:1px solid #d1d8dd;
border-bottom:1px solid @border-color;
margin: 2px 0px 5px 0px;
height: 60px;
margin-top: 0px;
@@ -134,12 +134,12 @@ body[data-route="pos"] {
}
.pos-payment-row:hover, .pos-keyboard-key:hover{
background-color: #FAFBFC;
background-color: @light-bg;
cursor: pointer;
}
.pos-keyboard-key, .delete-btn {
border: 1px solid #d1d8dd;
border: 1px solid @border-color;
height:85px;
width:85px;
margin:10px 10px;
@@ -150,7 +150,7 @@ body[data-route="pos"] {
}
.numeric-keypad {
border: 1px solid #d1d8dd;
border: 1px solid @border-color;
height:69px;
width:69px;
font-size:20px;
@@ -256,7 +256,7 @@ body[data-route="pos"] {
}
.selected-payment-mode {
background-color: #FAFBFC;
background-color: @light-bg;
cursor: pointer;
}
@@ -355,7 +355,7 @@ body[data-route="pos"] {
.image-field {
height: 140px;
.placeholder-text {
font-size: 50px;
}

View File

View File

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GST HSN Code', {
refresh: function(frm) {
}
});

View File

@@ -0,0 +1,103 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:hsn_code",
"beta": 0,
"creation": "2017-06-21 10:48:56.422086",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "hsn_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "HSN Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-29 21:28:09.053351",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST HSN Code",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "description",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

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

View File

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

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('GST Settings', {
refresh: function(frm) {
frm.add_custom_button('Send GST Update Reminder', () => {
return new Promise((resolve) => {
return frappe.call({
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_reminder'
}).always(() => { resolve(); });
});
});
$(frm.fields_dict.gst_summary.wrapper).empty().html(
`<table class="table table-bordered">
<tbody>
<tr>
<td>Total Addresses</td><td>${frm.doc.__onload.data.total_addresses}</td>
</tr><tr>
<td>Total Addresses with GST</td><td>${frm.doc.__onload.data.total_addresses_with_gstin}</td>
</tr>
</tbody></table>`
);
}
});

View File

@@ -0,0 +1,101 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-06-27 15:09:01.318003",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gst_summary",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "GST Summary",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "gstin_email_sent_on",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "GSTIN Email Sent On",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-28 16:20:21.206397",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, os
from frappe.utils import get_url, nowdate, date_diff
from frappe.model.document import Document
from frappe.contacts.doctype.contact.contact import get_default_contact
class EmailMissing(frappe.ValidationError): pass
class GSTSettings(Document):
def onload(self):
data = frappe._dict()
data.total_addresses = frappe.db.sql('''select count(*) from tabAddress where country = "India"''')
data.total_addresses_with_gstin = frappe.db.sql('''select distinct count(*)
from tabAddress where country = "India" and ifnull(gstin, '')!='' ''')
self.set_onload('data', data)
@frappe.whitelist()
def send_reminder():
frappe.has_permission('GST Settings', throw=True)
last_sent = frappe.db.get_single_value('GST Settings', 'gstin_email_sent_on')
if last_sent and date_diff(nowdate(), last_sent) < 3:
frappe.throw("Please wait 3 days before resending the reminder.")
frappe.db.set_value('GST Settings', 'GST Settings', 'gstin_email_sent_on', nowdate())
# enqueue if large number of customers, suppliser
frappe.enqueue('erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder_to_all_parties')
frappe.msgprint('Email Reminders will be sent to all parties with email contacts')
def send_gstin_reminder_to_all_parties():
parties = []
for address_name in frappe.db.sql('''select name
from tabAddress where country = "India" and ifnull(gstin, '')='' '''):
address = frappe.get_doc('Address', address_name[0])
for link in address.links:
party = frappe.get_doc(link.link_doctype, link.link_name)
if link.link_doctype in ('Customer', 'Supplier'):
t = (link.link_doctype, link.link_name, address.email_id)
if not t in parties:
parties.append(t)
sent_to = []
for party in parties:
# get email from default contact
try:
email_id = _send_gstin_reminder(party[0], party[1], party[2], sent_to)
sent_to.append(email_id)
except EmailMissing:
pass
@frappe.whitelist()
def send_gstin_reminder(party_type, party):
'''Send GSTIN reminder to one party (called from Customer, Supplier form)'''
frappe.has_permission(party_type, throw=True)
email = _send_gstin_reminder(party_type ,party)
if email:
frappe.msgprint('Reminder to update GSTIN Sent', title='Reminder sent', indicator='green')
def _send_gstin_reminder(party_type, party, default_email_id=None, sent_to=None):
'''Send GST Reminder email'''
email_id = frappe.db.get_value('Contact', get_default_contact(party_type, party), 'email_id')
if not email_id:
# get email from address
email_id = default_email_id
if not email_id:
frappe.throw('Email not found in default contact', exc=EmailMissing)
if sent_to and email_id in sent_to:
return
frappe.sendmail(
subject='Please update your GSTIN',
recipients=email_id,
message='''
<p>Hello,</p>
<p>Please help us send you GST Ready Invoices.</p>
<p>
<a href="{0}?party={1}">
Click here to update your GSTIN Number in our system
</a>
</p>
<p style="color: #aaa; font-size: 11px; margin-top: 30px;">
Get your GST Ready ERP system at <a href="https://erpnext.com">https://erpnext.com</a>
<br>
ERPNext is a free and open source ERP system.
</p>
'''.format(os.path.join(get_url(), '/regional/india/update-gstin'), party)
)
return email_id

View File

@@ -0,0 +1,76 @@
states = [
'',
'Andhra Pradesh',
'Arunachal Pradesh',
'Assam',
'Bihar',
'Chandigarh',
'Chattisgarh',
'Dadra and Nagar Haveli',
'Daman and Diu',
'Delhi',
'Goa',
'Gujarat',
'Haryana',
'Himachal Pradesh',
'Jammu and Kashmir',
'Jharkhand',
'Karnataka',
'Kerala',
'Lakshadweep Islands',
'Madhya Pradesh',
'Maharashtra',
'Manipur',
'Meghalaya',
'Mizoram',
'Nagaland',
'Odisha',
'Pondicherry',
'Punjab',
'Rajasthan',
'Sikkim',
'Tamil Nadu',
'Telangana',
'Tripura',
'Uttar Pradesh',
'Uttarakhand',
'West Bengal',
]
state_numbers = {
"Andhra Pradesh": "37",
"Arunachal Pradesh": "12",
"Assam": "18",
"Bihar": "10",
"Chandigarh": "04",
"Chattisgarh": "22",
"Dadra and Nagar Haveli": "26",
"Daman and Diu": "25",
"Delhi": "07",
"Goa": "30",
"Gujarat": "24",
"Haryana": "06",
"Himachal Pradesh": "02",
"Jammu and Kashmir": "01",
"Jharkhand": "20",
"Karnataka": "29",
"Kerala": "32",
"Lakshadweep Islands": "31",
"Madhya Pradesh": "23",
"Maharashtra": "27",
"Manipur": "14",
"Meghalaya": "17",
"Mizoram": "15",
"Nagaland": "13",
"Odisha": "21",
"Pondicherry": "34",
"Punjab": "03",
"Rajasthan": "08",
"Sikkim": "11",
"Tamil Nadu": "33",
"Telangana": "36",
"Tripura": "16",
"Uttar Pradesh": "35",
"Uttarakhand": "36",
"West Bengal": "37"
}

View File

@@ -0,0 +1,8 @@
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>
{% if state %}{{ state }}<br>{% endif -%}
{% if pincode %}{{ pincode }}<br>{% endif -%}
{{ country }}<br>
{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
{% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%}
{% if email_id %}Email: {{ email_id }}<br>{% endif -%}

View File

@@ -0,0 +1,177 @@
[
{
"state_number": "33",
"state_code": "TN",
"state_name": "Tamil Nadu"
},
{
"state_number": "35",
"state_code": "UP",
"state_name": "Uttar Pradesh"
},
{
"state_number": "36",
"state_code": "UT",
"state_name": "Uttarakhand"
},
{
"state_number": "37",
"state_code": "WB",
"state_name": "West Bengal"
},
{
"state_number": "16",
"state_code": "TR",
"state_name": "Tripura"
},
{
"state_number": "36",
"state_code": "TS",
"state_name": "Telangana"
},
{
"state_number": "11",
"state_code": "SK",
"state_name": "Sikkim"
},
{
"state_number": "08",
"state_code": "RJ",
"state_name": "Rajasthan"
},
{
"state_number": "03",
"state_code": "PB",
"state_name": "Punjab"
},
{
"state_number": "34",
"state_code": "PY",
"state_name": "Pondicherry"
},
{
"state_number": "21",
"state_code": "OR",
"state_name": "Odisha"
},
{
"state_number": "13",
"state_code": "NL",
"state_name": "Nagaland"
},
{
"state_number": "15",
"state_code": "MI",
"state_name": "Mizoram"
},
{
"state_number": "17",
"state_code": "ME",
"state_name": "Meghalaya"
},
{
"state_number": "14",
"state_code": "MN",
"state_name": "Manipur"
},
{
"state_number": "27",
"state_code": "MH",
"state_name": "Maharashtra"
},
{
"state_number": "23",
"state_code": "MP",
"state_name": "Madhya Pradesh"
},
{
"state_number": "31",
"state_code": "LD",
"state_name": "Lakshadweep Islands"
},
{
"state_number": "32",
"state_code": "KL",
"state_name": "Kerala"
},
{
"state_number": "29",
"state_code": "KA",
"state_name": "Karnataka"
},
{
"state_number": "20",
"state_code": "JH",
"state_name": "Jharkhand"
},
{
"state_number": "01",
"state_code": "JK",
"state_name": "Jammu and Kashmir"
},
{
"state_number": "02",
"state_code": "HP",
"state_name": "Himachal Pradesh"
},
{
"state_number": "06",
"state_code": "HR",
"state_name": "Haryana"
},
{
"state_number": "24",
"state_code": "GJ",
"state_name": "Gujarat"
},
{
"state_number": "30",
"state_code": "GA",
"state_name": "Goa"
},
{
"state_number": "07",
"state_code": "DL",
"state_name": "Delhi"
},
{
"state_number": "25",
"state_code": "DD",
"state_name": "Daman and Diu"
},
{
"state_number": "26",
"state_code": "DN",
"state_name": "Dadra and Nagar Haveli"
},
{
"state_number": "22",
"state_code": "CT",
"state_name": "Chattisgarh"
},
{
"state_number": "04",
"state_code": "CH",
"state_name": "Chandigarh"
},
{
"state_number": "10",
"state_code": "BH",
"state_name": "Bihar"
},
{
"state_number": "18",
"state_code": "AS",
"state_name": "Assam"
},
{
"state_number": "12",
"state_code": "AR",
"state_name": "Arunachal Pradesh"
},
{
"state_number": "37",
"state_code": "AD",
"state_name": "Andhra Pradesh (New)"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
erpnext.setup_gst_reminder_button = (doctype) => {
frappe.ui.form.on(doctype, {
refresh: (frm) => {
if(!frm.is_new()) {
var missing = false;
frm.doc.__onload.addr_list && frm.doc.__onload.addr_list.forEach((d) => {
if(!d.gstin) missing = true;
});
if (!missing) return;
frm.add_custom_button('Send GST Update Reminder', () => {
return new Promise((resolve) => {
return frappe.call({
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder',
args: {
party_type: frm.doc.doctype,
party: frm.doc.name,
}
}).always(() => { resolve(); });
});
});
}
}
});
};

View File

@@ -0,0 +1,132 @@
# 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, os, json
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.permissions import add_permission
from erpnext.regional.india import states
def setup(company=None, patch=True):
make_custom_fields()
add_permissions()
add_custom_roles_for_reports()
add_hsn_codes()
update_address_template()
if not patch:
make_fixtures()
def update_address_template():
with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f:
html = f.read()
address_template = frappe.db.get_value('Address Template', 'India')
if address_template:
frappe.db.set_value('Address Template', 'India', 'template', html)
else:
# make new html template for India
frappe.get_doc(dict(
doctype='Address Template',
country='India',
template=html
)).insert()
def add_hsn_codes():
if frappe.db.count('GST HSN Code') > 100:
return
with open(os.path.join(os.path.dirname(__file__), 'hsn_code_data.json'), 'r') as f:
hsn_codes = json.loads(f.read())
frappe.db.commit()
frappe.db.sql('truncate `tabGST HSN Code`')
for d in hsn_codes:
hsn_code = frappe.new_doc('GST HSN Code')
hsn_code.update(d)
hsn_code.name = hsn_code.hsn_code
hsn_code.db_insert()
frappe.db.commit()
def add_custom_roles_for_reports():
for report_name in ('GST Sales Register', 'GST Purchase Register',
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
frappe.get_doc(dict(
doctype='Custom Role',
report=report_name,
roles= [
dict(role='Accounts User'),
dict(role='Accounts Manager')
]
)).insert()
def add_permissions():
for doctype in ('GST HSN Code', 'GST Settings'):
add_permission(doctype, 'Accounts Manager', 0)
add_permission(doctype, 'All', 0)
def make_custom_fields():
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
insert_after='fax'),
dict(fieldname='gst_state', label='GST State', fieldtype='Select',
options='\n'.join(states), insert_after='gstin')
],
'Purchase Invoice': [
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
fieldtype='Data', insert_after='supplier_address',
options='supplier_address.gstin'),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='shipping_address',
options='shipping_address.gstin'),
],
'Sales Invoice': [
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address',
options='shipping_address_name.gstin'),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
options='company_address.gstin'),
],
'Item': [
dict(fieldname='gst_hsn_code', label='GST HSN Code',
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
],
'Sales Invoice Item': [
dict(fieldname='gst_hsn_code', label='GST HSN Code',
fieldtype='Data', options='item_code.gst_hsn_code',
insert_after='income_account'),
],
'Purchase Invoice Item': [
dict(fieldname='gst_hsn_code', label='GST HSN Code',
fieldtype='Data', options='item_code.gst_hsn_code',
insert_after='expense_account'),
]
}
for doctype, fields in custom_fields.items():
for df in fields:
create_custom_field(doctype, df)
def make_fixtures():
docs = [
{'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
{'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'},
{'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'},
{'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'},
{'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'},
{'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'}
]
for d in docs:
try:
doc = frappe.get_doc(d)
doc.flags.ignore_permissions = True
doc.insert()
except frappe.NameError:
pass

View File

@@ -0,0 +1,22 @@
import frappe, re
from frappe import _
from erpnext.regional.india import states, state_numbers
def validate_gstin_for_india(doc, method):
if not hasattr(doc, 'gstin'):
return
if doc.gstin:
if doc.gstin != "NA":
p = re.compile("[0-9]{2}[a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9a-zA-Z]{1}")
if not p.match(doc.gstin):
frappe.throw(_("Invalid GSTIN or Enter NA for Unregistered"))
if not doc.gst_state:
if doc.state in states:
doc.gst_state = doc.state
if doc.gst_state:
state_number = state_numbers[doc.gst_state]
if state_number != doc.gstin[:2]:
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number))

View File

View File

@@ -0,0 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
{% include "erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js" %}
frappe.query_reports["GST Itemised Purchase Register"] = frappe.query_reports["Item-wise Purchase Register"]

View File

@@ -0,0 +1,19 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-06-22 15:25:04.101930",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-06-22 15:25:10.749203",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Itemised Purchase Register",
"owner": "Administrator",
"ref_doctype": "Purchase Invoice",
"report_name": "GST Itemised Purchase Register",
"report_type": "Script Report",
"roles": []
}

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import _execute
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', width=120),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='HSN Code', width=120)
], additional_query_columns=[
'supplier_gstin',
'company_gstin',
'gst_hsn_code'
])

View File

@@ -0,0 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
{% include "erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js" %}
frappe.query_reports["GST Itemised Sales Register"] = frappe.query_reports["Item-wise Sales Register"]

View File

@@ -0,0 +1,19 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-06-22 15:24:43.083217",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-06-22 15:24:50.611910",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Itemised Sales Register",
"owner": "Administrator",
"ref_doctype": "Sales Invoice",
"report_name": "GST Itemised Sales Register",
"report_type": "Script Report",
"roles": []
}

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import _execute
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', width=120),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='HSN Code', width=120)
], additional_query_columns=[
'customer_gstin',
'company_gstin',
'gst_hsn_code'
])

View File

@@ -0,0 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
{% include "erpnext/accounts/report/purchase_register/purchase_register.js" %}
frappe.query_reports["GST Purchase Register"] = frappe.query_reports["Purchase Register"]

View File

@@ -0,0 +1,19 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-06-22 11:06:40.836073",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-06-22 12:17:15.487392",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Purchase Register",
"owner": "Administrator",
"ref_doctype": "Purchase Invoice",
"report_name": "GST Purchase Register",
"report_type": "Script Report",
"roles": []
}

View File

@@ -0,0 +1,16 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from erpnext.accounts.report.purchase_register.purchase_register import _execute
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', width=120),
dict(fieldtype='Data', label='Company GSTIN', width=120)
], additional_query_columns=[
'supplier_gstin',
'company_gstin'
])

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