Compare commits

..

83 Commits

Author SHA1 Message Date
Nabin Hait
537db4c2c7 Merge branch 'hotfix' 2017-12-25 13:38:06 +05:30
Nabin Hait
f4c5cf5bd0 bumped to version 9.2.24 2017-12-25 14:08:05 +06:00
rohitwaghchaure
bd5e01b09b [fix] Shipping address not fetch from purchase order in to purchase invoice & receipt. (#12134) 2017-12-25 11:28:07 +05:30
rohitwaghchaure
d8c6449f3a [Fix] Bom raw materials not in order in the stock entry (#12149) 2017-12-25 11:26:40 +05:30
rohitwaghchaure
75789b65c2 [Fix] Sales payment summary report (#12151) 2017-12-25 11:26:15 +05:30
rohitwaghchaure
443691aaf8 [Fix] Allow to change exchange rate in the payment entry if allow stale is enabled (#12128) 2017-12-22 10:59:01 +05:30
rohitwaghchaure
174900506e [HotFix] Validation issue for subcontract stock entry (#12127)
* [Fix] Validation issue for subcontract stock entry

* Update stock_entry.py
2017-12-21 11:28:01 +05:30
rohitwaghchaure
84da00da2f Allow to add items in manufacturing process which are not part of bom items (#12110) 2017-12-20 12:06:09 +05:30
rohitwaghchaure
78a17355be [fix] Item search in POS (#12037) 2017-12-15 15:38:12 +05:30
Nabin Hait
d257af910b Merge branch 'hotfix' 2017-12-15 12:53:55 +05:30
Nabin Hait
2f22d2b307 bumped to version 9.2.23 2017-12-15 13:23:54 +06:00
Pawan Mehta
d6cb617520 Fix 11948 - Sales Payment Summary (#11950)
* [fix] #11948

* [fix] #11948

* [fix] #11948

* codacy issues
2017-12-14 18:04:31 +05:30
Nabin Hait
aaf378e340 Validate numeric attribute value based on range defined in template (#11981) 2017-12-13 18:40:52 +05:30
Nabin Hait
96d6498226 Merge branch 'hotfix' 2017-12-12 19:17:51 +05:30
Nabin Hait
66456dae34 bumped to version 9.2.22 2017-12-12 19:47:51 +06:00
Nabin Hait
af9bdfeaa3 Fixed calculation of taxes and totals if tax is entered as Actual, for Deduction or valuation (#11965) 2017-12-12 18:50:05 +05:30
Nabin Hait
aab1182c73 Update stock_entry.js 2017-12-12 18:45:39 +05:30
Nabin Hait
de1e29bf1b Production Order fixes (#11951)
* Production Order from Sales Order fixes: Validate SO and set required items on save

* Codacy fixes
2017-12-12 13:22:48 +05:30
pawan
1892454036 Add Total Row 2017-12-11 17:48:56 +05:30
Nabin Hait
84a44f7758 Merge branch 'hotfix' 2017-12-07 12:03:40 +05:30
Nabin Hait
6674ba8bd1 bumped to version 9.2.21 2017-12-07 12:33:40 +06:00
Nabin Hait
5de499e5d5 Minor cleanups 2017-12-07 12:01:06 +05:30
pawan
271b7cd4f9 codacy issues 2017-12-07 12:01:00 +05:30
pawan
19f09b0b69 fix codacy issues 2017-12-07 12:00:06 +05:30
pawan
d8e91982ca Fixed Merge conflict 2017-12-07 12:00:01 +05:30
Nabin Hait
7ff6e378dd Merge branch 'hotfix' 2017-12-06 14:17:14 +05:30
Nabin Hait
7de5d3bb1d bumped to version 9.2.20 2017-12-06 14:47:13 +06:00
rohitwaghchaure
1b16bca843 [minor] Escape special characters (#11855) 2017-12-06 13:16:06 +05:30
tundebabzy
6a418f2a9b change Purchase Taxes and Charges default to 'Total' (#11857) 2017-12-06 13:15:33 +05:30
rohitwaghchaure
d52c64ff11 [fix] Show total for opening and closing dr/cr (#11860) 2017-12-06 13:14:28 +05:30
rohitwaghchaure
3a5ca927e7 [Fix] Asset depreciations and balances report showing wrong accumulated depreciation amount if multiple asset against same asset category (#11848)
* [Fix] Asset depreciations and balances report showing wrong accumulated depreciation amount if multiple asset against same asset category

* Update asset_depreciations_and_balances.py
2017-12-04 19:29:03 +05:30
rohitwaghchaure
148fccd45a [Fix] Wrong value showing in the email digest (#11840) 2017-12-04 13:36:01 +05:30
tundebabzy
3061fc92fd Batch Stock Items, having serial number can't be moved without inserting Serial Number (#11792) (#11813)
* if doctype is batch, add extra information to args

* automatically fetch serial numbers if possible

* take advantage of changes in make_stock_entry

* code clean up

* PEP 8 compliance

* fix bug that clears serial number
2017-12-04 11:23:21 +05:30
tundebabzy
1fb285c165 hide html example in print (#11830) 2017-12-04 11:13:36 +05:30
Saurabh
b36dc5e906 Merge branch 'hotfix' 2017-12-01 16:22:43 +05:30
Saurabh
a067ddbc20 bumped to version 9.2.19 2017-12-01 16:52:43 +06:00
Jamsheer
f4d9af1ab9 Fix Patch - remove company from patient (#11819) 2017-12-01 16:10:39 +05:30
rohitwaghchaure
b1ac979ac5 [fix] Do not allow zero valuation rate for serial no and fetch previous valuation rate for serial no (#11817) 2017-12-01 16:09:02 +05:30
Nabin Hait
7a294e6ef5 Update asset_category.json 2017-11-30 18:02:22 +05:30
Nabin Hait
5e801955f1 Update asset_category.json 2017-11-30 18:01:56 +05:30
Saurabh
aa25e95510 Merge branch 'hotfix' 2017-11-30 16:41:46 +05:30
Saurabh
f9509a084a bumped to version 9.2.18 2017-11-30 17:11:46 +06:00
Faris Ansari
ec3be9eebf [hotfix] Party Type name (#11797) 2017-11-30 15:53:39 +05:30
Nabin Hait
c5e0d22464 Update set_delivery_date_in_so_item.py 2017-11-30 15:52:47 +05:30
Rushabh Mehta
0154538c06 [fix] [minor] pos.js 2017-11-29 16:42:02 +05:30
rohitwaghchaure
1b344ca81e [Fix] POS not loading if pos profile not defined (#11778) 2017-11-29 16:21:51 +05:30
rohitwaghchaure
4a15711b04 Merge pull request #11768 from tundebabzy/issue-11749
add missing field and value parameters
2017-11-29 11:22:20 +05:30
tunde
0d82b6979e add missing field and value parameters 2017-11-28 23:30:03 +01:00
tundebabzy
bc7c387a0d set read only property properly (#11761) 2017-11-28 22:40:05 +05:30
Nabin Hait
35cd1d325f [fix] Set GST State code based on state, even if GSTIN not mentioned (#11755) 2017-11-28 13:01:01 +05:30
Saurabh
7b833802a9 Merge branch 'hotfix' 2017-11-28 11:00:17 +05:30
Saurabh
d86ace41a1 bumped to version 9.2.17 2017-11-28 11:30:17 +06:00
Jamsheer
b488475d92 Remove Company from Patient - Patches Added (#11716)
* Remove Company from Patient - Patches Added

* Update patient DOB field label to Date of birth

* Patient marital status default null

* Update patient.py
2017-11-28 10:47:06 +05:30
Saurabh
8eda0cc8ba [fix] validate bom if order type is subcontracting (#11705)
* [fix] validate bom if order type is subcontracting

* [fix] moved validation to server side
2017-11-28 10:41:35 +05:30
Saurabh
9d0092f89a [fix] pull source warehouse from production order child table (#11718) 2017-11-27 12:04:41 +05:30
Shreya Shah
e3d6d21ec5 [Fix] Item name and description in production order (#11723)
* fetch item name and description from bom

* Update production_order.py

* patch added

* Update set_item_name_in_production_order.py
2017-11-27 12:02:13 +05:30
Saurabh
ab5e77ecf1 [fix] do not pull disabled pos profiles (#11733) 2017-11-27 11:26:13 +05:30
Saurabh
41f60546a1 [fix] do not allow user to create party type (#11706) 2017-11-23 18:02:51 +05:30
Nabin Hait
cda4d50063 Fixed reserved qty for production logic and patch for reposting (#11691) 2017-11-23 13:05:43 +05:30
Zarrar
a90274fed9 linking issue in dashboard (#11701) 2017-11-23 12:19:40 +05:30
Jamsheer
1ce56316ea Populate patient_name in Healthcare Doctypes (#11690)
* On Cancel Consultation - Open Appointment - Delete Medical Record

* Add Filter on Account Selection - is_group: 0

* Patient Medical Record - List view Fixes

* Update consultation.py

* Set Appointment Refrence in Vital Signs

* Add Other in Gender Selection

* Populate patient_name in Healthcare Doctypes
2017-11-23 12:18:43 +05:30
Saurabh
7cf945c975 Merge branch 'hotfix' 2017-11-22 17:54:18 +05:30
Saurabh
4bc12b68e4 bumped to version 9.2.16 2017-11-22 18:24:18 +06:00
rohitwaghchaure
4dc5f0efaf [Fix] Item details not fetching if item has no default bom (#11688) 2017-11-22 15:21:47 +05:30
Nabin Hait
96abfd2ab9 [fix] In payment entry, run some events serially to avoid async issue 2017-11-22 15:13:16 +05:30
Makarand Bauskar
75443a94ee [minor] set the pos profile name while creating demo (#11664) 2017-11-21 16:12:40 +05:30
Nabin Hait
cc884578b5 Update sales_order.py 2017-11-21 12:24:03 +05:30
rohitwaghchaure
179e0c1d8d Added party name in accounts receivable/payable report (#11656) 2017-11-20 11:18:55 +05:30
rohitwaghchaure
34d6340be6 Merge pull request #11647 from rohitwaghchaure/pos_selling_price_issue
[fix] Price list not loaded from pos profile, auto set outstanding amount in the mode of payment
2017-11-18 21:33:32 +05:30
Rohit Waghchaure
77940493a8 [fix] Price list not loaded from pos profile, auto set outstanding amount in the mode of payment 2017-11-18 19:06:31 +05:30
Saurabh
a5b53e9480 Merge branch 'hotfix' 2017-11-17 14:55:23 +05:30
Saurabh
f773af6053 bumped to version 9.2.15 2017-11-17 15:25:23 +06:00
Saurabh
119a50e228 Merge pull request #11630 from saurabh6790/domain_settings_fix
[fix] set default language in local
2017-11-17 14:54:38 +05:30
Saurabh
11ec2c50e0 [fix] set default language in local 2017-11-17 14:51:08 +05:30
Saurabh
1e74519726 Merge branch 'hotfix' 2017-11-17 14:01:30 +05:30
Saurabh
05ed86a00e bumped to version 9.2.14 2017-11-17 14:31:29 +06:00
Saurabh
d40ae81fc9 Merge pull request #11627 from rohitwaghchaure/pos_redirect_issue
[fix] POS redirect issue
2017-11-17 13:55:10 +05:30
Rohit Waghchaure
44f7b157ff [fix] POS redirect issue 2017-11-17 13:52:11 +05:30
Saurabh
3499ba08df [fix] do not translate domains while creating db record (#11616) 2017-11-17 12:29:26 +05:30
rohitwaghchaure
51a397c97f [fix] Valuation rate in stock entry and code cleanup (#11614) 2017-11-16 18:23:16 +05:30
Manas Solanki
bb34c57603 link the address and contact with the sales partner (#11592) 2017-11-16 18:10:04 +05:30
tundebabzy
f7e6934d7c handle None case in update_reserved_qty_for_production (#11593) 2017-11-16 14:13:49 +05:30
rohitwaghchaure
21cbbae88f [fix] Payment reconcillation showing linked journal entries (#11611) 2017-11-16 14:05:57 +05:30
67 changed files with 985 additions and 518 deletions

View File

@@ -4,7 +4,7 @@ import inspect
import frappe
from erpnext.hooks import regional_overrides
__version__ = '9.2.13'
__version__ = '9.2.24'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -59,7 +59,7 @@
"label": "Depreciation Method",
"length": 0,
"no_copy": 0,
"options": "\nStraight Line\nDouble Declining Balance",
"options": "\nStraight Line\nDouble Declining Balance\nManual",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -228,7 +228,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 16:09:52.955332",
"modified": "2017-11-30 16:09:52.955332",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Asset Category",
@@ -284,4 +284,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}
}

View File

@@ -253,20 +253,24 @@ frappe.ui.form.on('Payment Entry', {
},
callback: function(r, rt) {
if(r.message) {
if(frm.doc.payment_type == "Receive") {
frm.set_value("paid_from", r.message.party_account);
frm.set_value("paid_from_account_currency", r.message.party_account_currency);
frm.set_value("paid_from_account_balance", r.message.account_balance);
} else if (frm.doc.payment_type == "Pay"){
frm.set_value("paid_to", r.message.party_account);
frm.set_value("paid_to_account_currency", r.message.party_account_currency);
frm.set_value("paid_to_account_balance", r.message.account_balance);
}
frm.set_value("party_balance", r.message.party_balance);
frm.events.get_outstanding_documents(frm);
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
frm.set_party_account_based_on_party = false;
frappe.run_serially([
() => {
if(frm.doc.payment_type == "Receive") {
frm.set_value("paid_from", r.message.party_account);
frm.set_value("paid_from_account_currency", r.message.party_account_currency);
frm.set_value("paid_from_account_balance", r.message.account_balance);
} else if (frm.doc.payment_type == "Pay"){
frm.set_value("paid_to", r.message.party_account);
frm.set_value("paid_to_account_currency", r.message.party_account_currency);
frm.set_value("paid_to_account_balance", r.message.account_balance);
}
},
() => frm.set_value("party_balance", r.message.party_balance),
() => frm.events.get_outstanding_documents(frm),
() => frm.events.hide_unhide_fields(frm),
() => frm.events.set_dynamic_labels(frm),
() => { frm.set_party_account_based_on_party = false; }
]);
}
}
});
@@ -404,7 +408,7 @@ frappe.ui.form.on('Payment Entry', {
}
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed());
frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
},
target_exchange_rate: function(frm) {
@@ -425,7 +429,7 @@ frappe.ui.form.on('Payment Entry', {
frm.set_paid_amount_based_on_received_amount = false;
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed());
frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
},
paid_amount: function(frm) {

View File

@@ -26,7 +26,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Series",
"length": 0,
@@ -432,7 +432,7 @@
"options": "<pre><h5>Message Example</h5>\n\n&lt;p&gt;Dear {{ doc.contact_person }},&lt;/p&gt;\n\n&lt;p&gt;Requesting payment for {{ doc.doctype }}, {{ doc.name }} for {{ doc.grand_total }}.&lt;/p&gt;\n\n&lt;a href=\"{{ payment_url }}\"&gt; click here to pay &lt;/a&gt;\n\n</pre>\n",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -728,7 +728,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:20.388372",
"modified": "2017-12-02 15:50:41.775006",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",

View File

@@ -24,11 +24,11 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
frappe.ui.form.on('POS Profile', {
setup: function(frm) {
frm.set_query("online_print_format", function() {
frm.set_query("print_format_for_online", function() {
return {
filters: [
['Print Format', 'doc_type', '=', 'Sales Invoice'],
['Print Format', 'print_format_type', '!=', 'Js'],
['Print Format', 'print_format_type', '=', 'Server'],
]
};
});

View File

@@ -19,7 +19,7 @@ class POSProfile(Document):
def check_for_duplicate(self):
res = frappe.db.sql("""select name, user from `tabPOS Profile`
where ifnull(user, '') = %s and name != %s and company = %s""",
where ifnull(user, '') = %s and name != %s and company = %s and ifnull(disabled, 0) != 1""",
(self.user, self.name, self.company))
if res:
if res[0][1]:

View File

@@ -12,8 +12,5 @@ class POSSettings(Document):
def set_link_for_pos(self):
link = 'pos' if self.use_pos_in_offline_mode else 'point-of-sale'
desktop_icon = frappe.db.get_value('Desktop Icon',
{'standard': 1, 'module_name': 'POS'}, 'name')
if desktop_icon:
frappe.db.set_value('Desktop Icon', desktop_icon, 'link', link)
frappe.db.sql(""" update `tabDesktop Icon` set link = '{0}'
where module_name like '%pos%'""".format(link))

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
@@ -10,20 +11,24 @@
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Valuation and Total",
"default": "Total",
"fieldname": "category",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Consider Tax or Charge for",
"length": 0,
"no_copy": 0,
@@ -34,6 +39,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,
@@ -41,6 +47,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -52,7 +59,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": "Add or Deduct",
"length": 0,
"no_copy": 0,
@@ -63,6 +72,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,
@@ -70,6 +80,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -80,7 +91,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": "Type",
"length": 0,
"no_copy": 0,
@@ -91,6 +104,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,
@@ -98,6 +112,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -109,7 +124,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": "Reference Row #",
"length": 0,
"no_copy": 0,
@@ -119,6 +136,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,
@@ -126,6 +144,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -137,7 +156,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": "Is this Tax included in Basic Rate?",
"length": 0,
"no_copy": 0,
@@ -146,6 +167,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
@@ -153,6 +175,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -163,13 +186,16 @@
"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,
@@ -177,6 +203,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -187,7 +214,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": "Account Head",
"length": 0,
"no_copy": 0,
@@ -198,6 +227,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,
@@ -205,6 +235,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -216,7 +247,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": "Cost Center",
"length": 0,
"no_copy": 0,
@@ -227,6 +260,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,
@@ -234,17 +268,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -255,6 +292,7 @@
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -263,6 +301,7 @@
"width": "300px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -273,7 +312,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,
@@ -281,6 +322,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,
@@ -288,6 +330,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -298,7 +341,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,
@@ -308,6 +353,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,
@@ -315,6 +361,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -325,7 +372,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,
@@ -333,6 +382,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,
@@ -340,6 +390,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -350,7 +401,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": "Amount",
"length": 0,
"no_copy": 0,
@@ -361,6 +414,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,
@@ -368,6 +422,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -378,7 +433,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": "Tax Amount After Discount Amount",
"length": 0,
"no_copy": 0,
@@ -388,6 +445,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,
@@ -395,6 +453,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -405,7 +464,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": "Total",
"length": 0,
"no_copy": 0,
@@ -416,6 +477,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,
@@ -423,6 +485,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -433,7 +496,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,
@@ -441,6 +506,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,
@@ -448,6 +514,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -458,7 +525,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 (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -468,6 +537,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,
@@ -475,6 +545,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -485,7 +556,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": "Total (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -495,6 +568,7 @@
"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,
@@ -502,6 +576,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -512,7 +587,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": "Tax Amount After Discount Amount",
"length": 0,
"no_copy": 0,
@@ -522,6 +599,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,
@@ -529,6 +607,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -539,7 +618,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": "Item Wise Tax Detail ",
"length": 0,
"no_copy": 0,
@@ -549,6 +630,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,
@@ -556,6 +638,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -565,8 +648,10 @@
"hidden": 1,
"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": "Parenttype",
"length": 0,
"no_copy": 0,
@@ -576,6 +661,7 @@
"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,
@@ -583,17 +669,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 1,
"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-08-26 03:20:22.118330",
"modified": "2017-12-05 13:37:44.483509",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",
@@ -602,5 +688,7 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 1,
"track_seen": 0
}

View File

@@ -247,7 +247,7 @@ class SalesInvoice(SellingController):
super(SalesInvoice, self).set_missing_values(for_validate)
if pos:
return {"print_format": pos.get("print_format") }
return {"print_format": pos.get("print_format_for_online") }
def update_time_sheet(self, sales_invoice):
for d in self.timesheets:

View File

@@ -36,8 +36,14 @@
<br>{%= data[i][__("Voucher No")] %}</td>
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer Name")] || data[i][__("Customer")] || data[i][__("Supplier Name")] || data[i][__("Supplier")] %}<br>{%= __("Remarks") %}:
{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
{% if(data[i][__("Customer Name")] && data[i][__("Customer Name")] != data[i][__("Customer")]) { %}
<br> {%= data[i][__("Customer Name")] %}
{% } else if(data[i][__("Supplier Name")] != data[i][__("Supplier")]) { %}
<br> {%= data[i][__("Supplier Name")] %}
{% } %}
{% } %}
<br>{%= __("Remarks") %}:
{%= data[i][__("Remarks")] %}
</td>
<td style="text-align: right">
@@ -66,8 +72,13 @@
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
<br>{%= __("Remarks") %}:
{% if(data[i][__("Customer Name")] && data[i][__("Customer Name")] != data[i][__("Customer")]) { %}
<br> {%= data[i][__("Customer Name")] %}
{% } else if(data[i][__("Supplier Name")] != data[i][__("Supplier")]) { %}
<br> {%= data[i][__("Supplier Name")] %}
{% } %}
{% } %}
<br>{%= __("Remarks") %}:
{%= data[i][__("Remarks")] %}
</td>
{% } else { %}

View File

@@ -86,17 +86,20 @@ def get_accumulated_depreciations(assets, filters):
for d in assets:
asset = frappe.get_doc("Asset", d.name)
asset_depreciations.setdefault(d.asset_category, frappe._dict({
"accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
"depreciation_amount_during_the_period": 0,
"depreciation_eliminated_during_the_period": 0
}))
if d.asset_category in asset_depreciations:
asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation
else:
asset_depreciations.setdefault(d.asset_category, frappe._dict({
"accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
"depreciation_amount_during_the_period": 0,
"depreciation_eliminated_during_the_period": 0
}))
depr = asset_depreciations[d.asset_category]
for schedule in asset.get("schedules"):
if getdate(schedule.schedule_date) < getdate(filters.from_date):
if not asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date):
if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date):
depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount)
elif getdate(schedule.schedule_date) <= getdate(filters.to_date):
depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)

View File

@@ -83,7 +83,7 @@ frappe.query_reports["General Ledger"] = {
return;
}
var fieldname = party_type.toLowerCase() + "_name";
var fieldname = frappe.scrub(party_type) + "_name";
frappe.db.get_value(party_type, party, fieldname, function(value) {
frappe.query_report_filters_by_name.party_name.set_value(value[fieldname]);
});

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Sales Payment Summary"] = {
"filters": [
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"reqd": 1,
"width": "80"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"reqd": 1,
"default": frappe.datetime.get_today()
},
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"owner",
"label": __("Owner"),
"fieldtype": "Link",
"options": "User",
"defaults": user
},
{
"fieldname":"is_pos",
"label": __("POS?"),
"fieldtype": "Check"
}
]
};

View File

@@ -0,0 +1,26 @@
{
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2017-11-03 16:31:45.757516",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-11-04 05:15:35.892659",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Payment Summary",
"owner": "Administrator",
"ref_doctype": "Sales Invoice",
"report_name": "Sales Payment Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
]
}

View File

@@ -0,0 +1,89 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr
def execute(filters=None):
columns, data = [], []
columns=get_columns()
data=get_sales_payment_data(filters, columns)
return columns, data
def get_columns():
return [
_("Date") + ":Date:80",
_("Owner") + "::150",
_("Payment Mode") + "::140",
_("Sales and Returns") + ":Currency/currency:120",
_("Taxes") + ":Currency/currency:120",
_("Payments") + ":Currency/currency:120",
_("Outstanding Amount") + ":Currency/currency:150",
]
def get_sales_payment_data(filters, columns):
sales_invoice_data = get_sales_invoice_data(filters)
data = []
mode_of_payments = get_mode_of_payments(filters)
for inv in sales_invoice_data:
mode_of_payment = inv["owner"]+cstr(inv["posting_date"])
row = [inv.posting_date, inv.owner,", ".join(mode_of_payments.get(mode_of_payment, [])),
inv.net_total,
inv.total_taxes, (inv.net_total + inv.total_taxes - inv.outstanding_amount),
inv.outstanding_amount]
data.append(row)
return data
def get_conditions(filters):
conditions = ""
if filters.get("from_date"): conditions += "a.posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and a.posting_date <= %(to_date)s"
if filters.get("company"): conditions += " and a.company=%(company)s"
if filters.get("customer"): conditions += " and a.customer = %(customer)s"
if filters.get("owner"): conditions += " and a.owner = %(owner)s"
if filters.get("is_pos"): conditions += " and a.is_pos = %(is_pos)s"
return conditions
def get_sales_invoice_data(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""
select
a.posting_date, a.owner,
sum(a.net_total) as "net_total",
sum(a.total_taxes_and_charges) as "total_taxes",
sum(a.base_paid_amount) as "paid_amount",
sum(a.outstanding_amount) as "outstanding_amount"
from `tabSales Invoice` a
where a.docstatus = 1
and {conditions}
group by
a.owner, a.posting_date
""".format(conditions=conditions), filters, as_dict=1)
def get_mode_of_payments(filters):
mode_of_payments = {}
invoice_list = get_invoices(filters)
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
if invoice_list:
inv_mop = frappe.db.sql("""select a.owner,a.posting_date,b.mode_of_payment
from `tabSales Invoice` a, `tabSales Invoice Payment` b
where a.name = b.parent
and a.name in ({invoice_list_names})
union
select a.owner,a.posting_date,b.mode_of_payment
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
where a.name = c.reference_name
and b.name = c.parent
and a.name in ({invoice_list_names})
""".format(invoice_list_names=invoice_list_names), as_dict=1)
for d in inv_mop:
mode_of_payments.setdefault(d["owner"]+cstr(d["posting_date"]), []).append(d.mode_of_payment)
return mode_of_payments
def get_invoices(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""select a.name
from `tabSales Invoice` a
where a.docstatus = 1 and {conditions}""".format(conditions=conditions),
filters, as_dict=1)

View File

@@ -134,8 +134,12 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters,
"account": "'" + _("Total") + "'",
"account_name": "'" + _("Total") + "'",
"warn_if_negative": True,
"opening_debit": 0.0,
"opening_credit": 0.0,
"debit": 0.0,
"credit": 0.0,
"closing_debit": 0.0,
"closing_credit": 0.0,
"parent_account": None,
"indent": 0,
"has_value": True,
@@ -156,7 +160,10 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters,
total_row["debit"] += d["debit"]
total_row["credit"] += d["credit"]
total_row["opening_debit"] += d["opening_debit"]
total_row["opening_credit"] += d["opening_credit"]
total_row["closing_debit"] += (d["opening_debit"] + d["debit"])
total_row["closing_credit"] += (d["opening_credit"] + d["credit"])
return total_row

View File

@@ -593,7 +593,9 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
select ifnull(sum({payment_dr_or_cr}), 0)
from `tabGL Entry` payment_gl_entry
where payment_gl_entry.against_voucher_type = invoice_gl_entry.voucher_type
and payment_gl_entry.against_voucher = invoice_gl_entry.against_voucher
and if(invoice_gl_entry.voucher_type='Journal Entry',
payment_gl_entry.against_voucher = invoice_gl_entry.voucher_no,
payment_gl_entry.against_voucher = invoice_gl_entry.against_voucher)
and payment_gl_entry.party_type = invoice_gl_entry.party_type
and payment_gl_entry.party = invoice_gl_entry.party
and payment_gl_entry.account = invoice_gl_entry.account

View File

@@ -51,6 +51,7 @@ class PurchaseOrder(BuyingController):
self.validate_with_previous_doc()
self.validate_for_subcontracting()
self.validate_minimum_order_qty()
self.validate_bom_for_subcontracting_items()
self.create_raw_materials_supplied("supplied_items")
self.set_received_qty_for_drop_ship_items()
@@ -95,6 +96,13 @@ class PurchaseOrder(BuyingController):
frappe.throw(_("Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item).").format(item_code,
qty, itemwise_min_order_qty.get(item_code)))
def validate_bom_for_subcontracting_items(self):
if self.is_subcontracted == "Yes":
for item in self.items:
if not item.bom:
frappe.throw(_("BOM is not specified for subcontracting item {0} at row {1}"\
.format(item.item_code, item.idx)))
def get_schedule_dates(self):
for d in self.get('items'):
if d.material_request_item and not d.schedule_date:

View File

@@ -468,6 +468,12 @@ def get_data():
"name": "Customer Credit Balance",
"doctype": "Customer"
},
{
"type": "report",
"is_query_report": True,
"name": "Sales Payment Summary",
"doctype": "Sales Invoice"
}
]
},
{

View File

@@ -171,7 +171,7 @@ class BuyingController(StockController):
for item in self.get("items"):
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
item.rm_supp_cost = 0.0
if item.item_code in self.sub_contracted_items:
if item.bom and item.item_code in self.sub_contracted_items:
self.update_raw_materials_supplied(item, raw_material_table)
if [item.item_code, item.name] not in parent_items:

View File

@@ -56,7 +56,7 @@ def validate_item_variant_attributes(item, args=None):
if not args:
args = {d.attribute.lower():d.attribute_value for d in item.attributes}
attribute_values, numeric_values = get_attribute_values()
attribute_values, numeric_values = get_attribute_values(item)
for attribute, value in args.items():
if not value:
@@ -96,16 +96,17 @@ def validate_item_attribute_value(attributes_list, attribute, attribute_value, i
frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values for Item {2}").format(
attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Invalid Attribute'))
def get_attribute_values():
def get_attribute_values(item):
if not frappe.flags.attribute_values:
attribute_values = {}
numeric_values = {}
for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"]):
attribute_values.setdefault(t.parent.lower(), []).append(t.attribute_value)
for t in frappe.get_all('Item Attribute',
fields=["name", "from_range", "to_range", "increment"], filters={'numeric_values': 1}):
numeric_values[t.name.lower()] = t
for t in frappe.get_all('Item Variant Attribute',
fields=["attribute", "from_range", "to_range", "increment"],
filters={'numeric_values': 1, 'parent': item.variant_of}):
numeric_values[t.attribute.lower()] = t
frappe.flags.attribute_values = attribute_values
frappe.flags.numeric_values = numeric_values

View File

@@ -399,7 +399,8 @@ class calculate_taxes_and_totals(object):
for tax in self.doc.get("taxes"):
if tax.charge_type == "Actual":
actual_taxes_dict.setdefault(tax.idx, tax.tax_amount)
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
actual_taxes_dict.setdefault(tax.idx, tax_amount)
elif tax.row_id in actual_taxes_dict:
actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)

View File

@@ -5,6 +5,7 @@ def get_data():
'fieldname': 'prevdoc_docname',
'non_standard_fieldnames': {
'Supplier Quotation': 'opportunity',
'Quotation': 'opportunity'
},
'transactions': [
{

View File

@@ -348,8 +348,10 @@ def setup_budget():
budget.action_if_annual_budget_exceeded = "Warn"
expense_ledger_count = frappe.db.count("Account", {"is_group": "0", "root_type": "Expense"})
add_random_children(budget, "accounts", rows=random.randint(10, expense_ledger_count), randomize = { "account": ("Account", {"is_group": "0", "root_type": "Expense"})
}, unique="account")
add_random_children(budget, "accounts", rows=random.randint(10, expense_ledger_count),
randomize = {
"account": ("Account", {"is_group": "0", "root_type": "Expense"})
}, unique="account")
for d in budget.accounts:
d.budget_amount = random.randint(5, 100) * 10000
@@ -361,6 +363,7 @@ def setup_pos_profile():
company_abbr = frappe.db.get_value("Company", erpnext.get_default_company(), "abbr")
pos = frappe.new_doc('POS Profile')
pos.user = frappe.db.get_global('demo_accounts_user')
pos.pos_profile_name = "Demo POS Profile"
pos.naming_series = 'SINV-'
pos.update_stock = 0
pos.write_off_account = 'Cost of Goods Sold - '+ company_abbr

View File

@@ -139,6 +139,7 @@ var btn_create_vital_signs = function (frm) {
}
frappe.route_options = {
"patient": frm.doc.patient,
"appointment": frm.doc.appointment
};
frappe.new_doc("Vital Signs");
};

View File

@@ -216,7 +216,7 @@
"label": "Gender",
"length": 0,
"no_copy": 0,
"options": "\nMale\nFemale",
"options": "\nMale\nFemale\nOther",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -1004,7 +1004,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-05 12:13:52.596750",
"modified": "2017-11-22 14:03:30.434304",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Consultation",

View File

@@ -114,7 +114,7 @@
"columns": 0,
"fieldname": "patient_name",
"fieldtype": "Data",
"hidden": 1,
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
@@ -185,7 +185,7 @@
"label": "Gender",
"length": 0,
"no_copy": 0,
"options": "\nMale\nFemale",
"options": "\nMale\nFemale\nOther",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -1388,7 +1388,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-05 12:14:57.078823",
"modified": "2017-11-22 14:32:27.994634",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Lab Test",

View File

@@ -126,7 +126,7 @@
"label": "Gender",
"length": 0,
"no_copy": 0,
"options": "\nMale\nFemale",
"options": "\nMale\nFemale\nOther",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -185,7 +185,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "DOB",
"label": "Date of birth",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -353,37 +353,6 @@
"set_only_once": 1,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"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": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -884,7 +853,7 @@
"label": "Marital Status",
"length": 0,
"no_copy": 0,
"options": "Single\nMarried\nDivorced\nWidow",
"options": "\nSingle\nMarried\nDivorced\nWidow",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -1274,7 +1243,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 50,
"modified": "2017-10-04 17:41:03.219934",
"modified": "2017-11-24 12:39:33.061005",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient",

View File

@@ -69,7 +69,10 @@ class Patient(Document):
frappe.db.set_value("Patient", self.name, "disabled", 0)
send_registration_sms(self)
if(frappe.get_value("Healthcare Settings", None, "registration_fee")>0):
sales_invoice = make_invoice(self.name, self.company)
company = frappe.defaults.get_user_default('company')
if not company:
company = frappe.db.get_value("Global Defaults", None, "default_company")
sales_invoice = make_invoice(self.name, company)
sales_invoice.save(ignore_permissions=True)
return {'invoice': sales_invoice.name}
@@ -110,7 +113,7 @@ def make_invoice(patient, company):
return sales_invoice
@frappe.whitelist()
def get_patient_detail(patient, company=None):
def get_patient_detail(patient):
patient_dict = frappe.db.sql("""select * from tabPatient where name=%s""", (patient), as_dict=1)
if not patient_dict:
frappe.throw("Patient not found")

View File

@@ -185,6 +185,7 @@ var btn_create_vital_signs = function (frm) {
}
frappe.route_options = {
"patient": frm.doc.patient,
"appointment": frm.doc.name,
};
frappe.new_doc("Vital Signs");
};

View File

@@ -165,6 +165,100 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "patient_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Name",
"length": 0,
"no_copy": 0,
"options": "patient.patient_name",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "patient_sex",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Gender",
"length": 0,
"no_copy": 1,
"options": "patient.sex",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"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": "patient_age",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Age",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -440,158 +534,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "patient_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "patient",
"fieldname": "patient_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 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": "patient_sex",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Gender",
"length": 0,
"no_copy": 1,
"options": "patient.sex",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"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": "patient_age",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Age",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -756,7 +698,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-25 23:33:36.060803",
"modified": "2017-11-22 16:32:57.240736",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Appointment",

View File

@@ -43,6 +43,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "patient_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Patient Name",
"length": 0,
"no_copy": 0,
"options": "patient.patient_name",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -751,7 +782,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-04 16:08:36.340607",
"modified": "2017-11-22 17:31:16.620650",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Vital Signs",

View File

@@ -519,6 +519,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
query = """select
bom_item.item_code,
bom_item.idx,
item.item_name,
sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
item.description,

View File

@@ -157,6 +157,7 @@ frappe.ui.form.on("Production Order", {
item: frm.doc.production_item,
project: frm.doc.project
},
freeze: true,
callback: function(r) {
if(r.message) {
erpnext.in_production_item_onchange = true;
@@ -184,6 +185,7 @@ frappe.ui.form.on("Production Order", {
return frm.call({
doc: frm.doc,
method: "get_items_and_operations_from_bom",
freeze: true,
callback: function(r) {
if(r.message["set_scrap_wh_mandatory"]){
frm.toggle_reqd("scrap_warehouse", true);

View File

@@ -43,10 +43,7 @@ class ProductionOrder(Document):
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
if not self.get("required_items"):
self.set_required_items()
else:
self.set_available_qty()
self.set_required_items(reset_only_qty = len(self.get("required_items")))
def validate_sales_order(self):
if self.sales_order:
@@ -57,6 +54,19 @@ class ProductionOrder(Document):
and so.docstatus = 1 and so_item.item_code=%s
""", (self.sales_order, self.production_item), as_dict=1)
if not so:
so = frappe.db.sql("""
select
so.name, so_item.delivery_date, so.project
from
`tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
where so.name=%s
and so.name=so_item.parent
and so.name=packed_item.parent
and so_item.item_code = packed_item.parent_item
and so.docstatus = 1 and packed_item.item_code=%s
""", (self.sales_order, self.production_item), as_dict=1)
if len(so):
if not self.expected_delivery_date:
self.expected_delivery_date = so[0].delivery_date
@@ -431,19 +441,27 @@ class ProductionOrder(Document):
if self.wip_warehouse:
d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
def set_required_items(self):
def set_required_items(self, reset_only_qty=False):
'''set required_items for production to keep track of reserved qty'''
self.required_items = []
if not reset_only_qty:
self.required_items = []
if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
for item in sorted(item_dict.values(), key=lambda d: d['idx']):
self.append('required_items', {
'item_code': item.item_code,
'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse
})
if reset_only_qty:
for d in self.get("required_items"):
d.required_qty = item_dict.get(d.item_code).get("qty")
else:
for item in sorted(item_dict.values(), key=lambda d: d['idx']):
self.append('required_items', {
'item_code': item.item_code,
'item_name': item.item_name,
'description': item.description,
'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse
})
self.set_available_qty()

View File

@@ -15,62 +15,66 @@ def get_item_list(prod_list, filters):
out = []
#Add a row for each item/qty
for prod_order in prod_list:
prod_details = frappe.db.get_value("Production Order", prod_order.name,
["bom_no", "source_warehouse", "qty", "produced_qty"], as_dict=1)
for prod_details in prod_list:
desc = frappe.db.get_value("BOM", prod_details.bom_no, "description")
item_list = frappe.db.sql("""SELECT
bom_item.item_code as item_code,
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
ON bom_item.item_code = ledger.item_code
AND ledger.warehouse = ifnull(%(warehouse)s,%(filterhouse)s)
WHERE
bom.name = bom_item.parent
and bom.name = %(bom)s
GROUP BY
bom_item.item_code""",
{"bom": prod_details.bom_no, "warehouse": prod_details.source_warehouse,
"filterhouse": filters.warehouse}, as_dict=1)
stock_qty = 0
count = 0
buildable_qty = prod_details.qty
for item in item_list:
count = count + 1
if item.build_qty >= (prod_details.qty - prod_details.produced_qty):
stock_qty = stock_qty + 1
elif buildable_qty >= item.build_qty:
buildable_qty = item.build_qty
if count == stock_qty:
build = "Y"
else:
build = "N"
row = frappe._dict({
"production_order": prod_order.name,
"status": prod_order.status,
"req_items": cint(count),
"instock": stock_qty,
"description": desc,
"bom_no": prod_details.bom_no,
"qty": prod_details.qty,
"buildable_qty": buildable_qty,
"ready_to_build": build
})
out.append(row)
for prod_item_details in frappe.db.get_values("Production Order Item",
{"parent": prod_details.name}, ["item_code", "source_warehouse"], as_dict=1):
item_list = frappe.db.sql("""SELECT
bom_item.item_code as item_code,
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
ON bom_item.item_code = ledger.item_code
AND ledger.warehouse = ifnull(%(warehouse)s,%(filterhouse)s)
WHERE
bom.name = bom_item.parent
and bom_item.item_code = %(item_code)s
and bom.name = %(bom)s
GROUP BY
bom_item.item_code""",
{"bom": prod_details.bom_no, "warehouse": prod_item_details.source_warehouse,
"filterhouse": filters.warehouse, "item_code": prod_item_details.item_code}, as_dict=1)
stock_qty = 0
count = 0
buildable_qty = prod_details.qty
for item in item_list:
count = count + 1
if item.build_qty >= (prod_details.qty - prod_details.produced_qty):
stock_qty = stock_qty + 1
elif buildable_qty >= item.build_qty:
buildable_qty = item.build_qty
if count == stock_qty:
build = "Y"
else:
build = "N"
row = frappe._dict({
"production_order": prod_details.name,
"status": prod_details.status,
"req_items": cint(count),
"instock": stock_qty,
"description": desc,
"source_warehouse": prod_item_details.source_warehouse,
"item_code": prod_item_details.item_code,
"bom_no": prod_details.bom_no,
"qty": prod_details.qty,
"buildable_qty": buildable_qty,
"ready_to_build": build
})
out.append(row)
return out
def get_production_orders():
out = frappe.get_all("Production Order", filters={"docstatus": 1, "status": ( "!=","Completed")}, fields=["name","status"], order_by='name')
out = frappe.get_all("Production Order", filters={"docstatus": 1, "status": ( "!=","Completed")},
fields=["name","status", "bom_no", "qty", "produced_qty"], order_by='name')
return out
def get_columns():
@@ -93,6 +97,18 @@ def get_columns():
"options": "",
"width": 230
}, {
"fieldname": "item_code",
"label": "Item Code",
"fieldtype": "Link",
"options": "Item",
"width": 110
},{
"fieldname": "source_warehouse",
"label": "Source Warehouse",
"fieldtype": "Link",
"options": "Warehouse",
"width": 110
},{
"fieldname": "qty",
"label": "Qty to Build",
"fieldtype": "Data",

View File

@@ -460,3 +460,7 @@ erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings
execute:frappe.delete_doc_if_exists("DocType", "Program Fee")
erpnext.patches.v9_0.update_employee_loan_details
erpnext.patches.v9_2.delete_healthcare_domain_default_items
erpnext.patches.v9_2.rename_translated_domains_in_en
erpnext.patches.v9_2.repost_reserved_qty_for_production
erpnext.patches.v9_2.remove_company_from_patient
erpnext.patches.v9_2.set_item_name_in_production_order

View File

@@ -18,4 +18,6 @@ def execute():
and so.order_type = 'Sales'
and (so_item.delivery_date is null or so_item.delivery_date = ''
or so_item.delivery_date = '0000-00-00')
""")
and (so.delivery_date is not null and so.delivery_date != ''
and so.delivery_date != '0000-00-00')
""")

View File

@@ -0,0 +1,6 @@
import frappe
def execute():
if frappe.db.exists("DocType", "Patient"):
if 'company' in frappe.db.get_table_columns("Patient"):
frappe.db.sql("alter table `tabPatient` drop column company")

View File

@@ -0,0 +1,31 @@
import frappe
from frappe import _
def execute():
language = frappe.get_single("System Settings").language
if language and language.startswith('en'): return
frappe.local.lang = language
all_domains = frappe.get_hooks("domains")
for domain in all_domains:
translated_domain = _(domain, lang=language)
if frappe.db.exists("Domain", translated_domain):
frappe.rename_doc("Domain", translated_domain, domain, ignore_permissions=True, merge=True)
domain_settings = frappe.get_single("Domain Settings")
active_domains = [d.domain for d in domain_settings.active_domains]
try:
for domain in active_domains:
domain = frappe.get_doc("Domain", domain)
domain.setup_domain()
if int(frappe.db.get_single_value('System Settings', 'setup_complete')):
domain.setup_sidebar_items()
domain.setup_desktop_icons()
domain.set_default_portal_role()
except frappe.LinkValidationError:
pass

View File

@@ -0,0 +1,7 @@
import frappe
def execute():
bins = frappe.db.sql("select name from `tabBin` where reserved_qty_for_production > 0")
for d in bins:
bin_doc = frappe.get_doc("Bin", d[0])
bin_doc.update_reserved_qty_for_production()

View File

@@ -0,0 +1,11 @@
import frappe
def execute():
frappe.db.sql("""
update `tabBOM Item` bom, `tabProduction Order Item` po_item
set po_item.item_name = bom.item_name,
po_item.description = bom.description
where po_item.item_code = bom.item_code
and (po_item.item_name is null or po_item.description is null)
""")

View File

@@ -34,7 +34,7 @@
margin-left: 15px;
}
.cart-wrapper {
margin-bottom: 10px;
margin-bottom: 12px;
}
.cart-wrapper .list-item__content:not(:first-child) {
justify-content: flex-end;
@@ -121,7 +121,6 @@ input[type=number]::-webkit-outer-spin-button {
border-collapse: collapse;
cursor: pointer;
display: table;
margin: auto;
}
.num-row {
display: table-row;

View File

@@ -521,9 +521,11 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
var actual_taxes_dict = {};
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
if (tax.charge_type == "Actual")
actual_taxes_dict[tax.idx] = tax.tax_amount;
else if (actual_taxes_dict[tax.row_id] !== null) {
if (tax.charge_type == "Actual") {
var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount;
tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
actual_taxes_dict[tax.idx] = tax_amount;
} else if (actual_taxes_dict[tax.row_id] !== null) {
var actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100;
actual_taxes_dict[tax.idx] = actual_tax_amount;
}

View File

@@ -550,7 +550,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}
// Make read only if Accounts Settings doesn't allow stale rates
this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed());
this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
},
set_actual_charges_based_on_currency: function() {

View File

@@ -171,7 +171,10 @@ erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
erpnext.utils.get_shipping_address = function(frm, callback){
frappe.call({
method: "frappe.contacts.doctype.address.address.get_shipping_address",
args: {company: frm.doc.company},
args: {
company: frm.doc.company,
address: frm.doc.shipping_address
},
callback: function(r){
if(r.message){
frm.set_value("shipping_address", r.message[0]) //Address title or name

View File

@@ -50,7 +50,7 @@
}
.cart-wrapper {
margin-bottom: 10px;
margin-bottom: 12px;
.list-item__content:not(:first-child) {
justify-content: flex-end;
}
@@ -155,7 +155,6 @@ input[type=number]::-webkit-outer-spin-button {
border-collapse: collapse;
cursor: pointer;
display: table;
margin: auto;
}
.num-row {
display: table-row;

View File

@@ -14,15 +14,15 @@ def validate_gstin_for_india(doc, method):
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 not doc.gst_state:
if doc.state in states:
doc.gst_state = doc.state
if doc.gst_state:
doc.gst_state_number = state_numbers[doc.gst_state]
if doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
.format(doc.gst_state_number))
if doc.gst_state:
doc.gst_state_number = state_numbers[doc.gst_state]
if doc.gstin and doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
.format(doc.gst_state_number))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):

View File

@@ -103,7 +103,7 @@ class SalesOrder(SellingController):
def validate_delivery_date(self):
if self.order_type == 'Sales':
if not self.delivery_date:
self.delivery_date = max([d.delivery_date for d in self.get("items")])
self.delivery_date = max([d.delivery_date for d in self.get("items") if d.delivery_date])
if self.delivery_date:
for d in self.get("items"):
@@ -762,10 +762,15 @@ def make_production_orders(items, sales_order, company, project=None):
out = []
for i in items:
if not i.get("bom"):
frappe.throw(_("Please select BOM against item {0}").format(i.get("item_code")))
if not i.get("pending_qty"):
frappe.throw(_("Please select Qty against item {0}").format(i.get("item_code")))
production_order = frappe.get_doc(dict(
doctype='Production Order',
production_item=i['item_code'],
bom_no=i['bom'],
bom_no=i.get('bom'),
qty=i['pending_qty'],
company=company,
sales_order=sales_order,

View File

@@ -53,8 +53,6 @@ erpnext.pos.PointOfSale = class PointOfSale {
() => this.setup_pos_profile(),
() => this.make_new_invoice(),
() => {
frappe.timeout(1);
this.make_items();
this.bind_events();
frappe.dom.unfreeze();
},
@@ -208,7 +206,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
select_batch_and_serial_no(item) {
erpnext.show_serial_batch_selector(this.frm, item, () => {
this.update_item_in_frm(item)
this.update_item_in_frm(item, 'qty', item.qty)
.then(() => {
// update cart
if (item.qty === 0) {
@@ -324,15 +322,17 @@ erpnext.pos.PointOfSale = class PointOfSale {
make_new_invoice() {
return frappe.run_serially([
() => this.make_sales_invoice_frm(),
() => this.set_pos_profile_data(),
() => {
if (this.cart) {
this.cart.frm = this.frm;
this.cart.reset();
} else {
this.make_items();
this.make_cart();
}
this.toggle_editing(true);
}
},
]);
}
@@ -359,12 +359,32 @@ erpnext.pos.PointOfSale = class PointOfSale {
if(!frm.doc.company) {
frm.set_value('company', pos_profile.company);
}
frm.set_value('is_pos', 1);
frm.meta.default_print_format = 'POS Invoice';
frm.doc.is_pos = 1;
return frm;
}
}
set_pos_profile_data() {
return new Promise(resolve => {
return this.frm.call({
doc: this.frm.doc,
method: "set_missing_values",
}).then((r) => {
if(!r.exc) {
this.frm.script_manager.trigger("update_stock");
frappe.model.set_default_values(this.frm.doc);
this.frm.cscript.calculate_taxes_and_totals();
if (r.message) {
this.frm.meta.default_print_format = r.message.print_format || 'POS Invoice';
}
}
resolve();
})
})
}
prepare_menu() {
var me = this;
this.page.clear_menu();
@@ -392,9 +412,6 @@ erpnext.pos.PointOfSale = class PointOfSale {
if(this.frm.doc.docstatus !== 1) return;
this.page.set_secondary_action(__("Print"), () => {
if (this.pos_profile && this.pos_profile.print_format_for_online) {
this.frm.meta.default_print_format = this.pos_profile.print_format_for_online;
}
this.frm.print_preview.printit(true);
});
@@ -899,7 +916,7 @@ class POSItems {
this.search_field = frappe.ui.form.make_control({
df: {
fieldtype: 'Data',
label: 'Search Item ( Ctrl + i )',
label: 'Search Item (Ctrl + i)',
placeholder: 'Search by item code, serial number, batch no or barcode'
},
parent: this.wrapper.find('.search-field'),
@@ -963,7 +980,7 @@ class POSItems {
}
curr_row += all_items[i];
if(i == all_items.length - 1 && all_items.length % 4 !== 0) {
if(i == all_items.length - 1) {
row_items.push(curr_row);
}
}
@@ -991,7 +1008,7 @@ class POSItems {
this.get_items({search_value: search_term, item_group })
.then(({ items, serial_no, batch_no, barcode }) => {
if (search_term) {
if (search_term && !barcode) {
this.search_index[search_term] = items;
}
@@ -1264,6 +1281,16 @@ class Payment {
$(this.dialog.body).find('.input-with-feedback').focusin(function() {
me.numpad.reset_value();
me.fieldname = $(this).prop('dataset').fieldname;
if (me.frm.doc.outstanding_amount > 0 &&
!in_list(['write_off_amount', 'change_amount'], me.fieldname)) {
me.frm.doc.payments.forEach((data) => {
if (data.mode_of_payment == me.fieldname && !data.amount) {
me.dialog.set_value(me.fieldname,
me.frm.doc.outstanding_amount / me.frm.doc.conversion_rate);
return;
}
})
}
});
}
@@ -1403,4 +1430,4 @@ class Payment {
this.dialog.set_value("paid_amount", this.frm.doc.paid_amount);
this.dialog.set_value("outstanding_amount", this.frm.doc.outstanding_amount);
}
}
}

View File

@@ -232,7 +232,7 @@ class EmailDigest(Document):
"new_quotations","pending_quotations","sales_order","purchase_order","pending_sales_orders","pending_purchase_orders",
"invoiced_amount", "payables", "bank_balance", "credit_balance"):
if self.get(key):
cache_key = "email_digest:card:{0}:{1}:{2}".format(self.company, self.frequency, key)
cache_key = "email_digest:card:{0}:{1}:{2}:{3}".format(self.company, self.frequency, key, self.from_date)
card = cache.get(cache_key)
if card:

View File

@@ -81,7 +81,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
@frappe.whitelist(allow_guest=True)
def get_product_list_for_group(product_group=None, start=0, limit=10, search=None):
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)])
child_groups = ", ".join(['"' + frappe.db.escape(i[0]) + '"' for i in get_child_groups(product_group)])
# base query
query = """select name, item_name, item_code, route, image, website_image, thumbnail, item_group,

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:party_type",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,17 +45,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"in_create": 1,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-20 13:25:04.456818",
"modified": "2017-11-23 17:46:27.075001",
"modified_by": "Administrator",
"module": "Setup",
"name": "Party Type",
@@ -64,8 +66,8 @@
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
@@ -78,14 +80,14 @@
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
@@ -98,14 +100,14 @@
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
@@ -118,10 +120,10 @@
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
"write": 0
}
],
"quick_entry": 1,
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,

View File

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

View File

@@ -3,7 +3,7 @@
frappe.ui.form.on('Sales Partner', {
refresh: function(frm) {
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Sales Person'}
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Sales Partner'}
if(frm.doc.__islocal){
hide_field(['address_html', 'contact_html', 'address_contacts']);

View File

@@ -14,12 +14,12 @@ default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
def install(country=None):
records = [
# domains
{ 'doctype': 'Domain', 'domain': _('Distribution')},
{ 'doctype': 'Domain', 'domain': _('Manufacturing')},
{ 'doctype': 'Domain', 'domain': _('Retail')},
{ 'doctype': 'Domain', 'domain': _('Services')},
{ 'doctype': 'Domain', 'domain': _('Education')},
{ 'doctype': 'Domain', 'domain': _('Healthcare')},
{ 'doctype': 'Domain', 'domain': 'Distribution'},
{ 'doctype': 'Domain', 'domain': 'Manufacturing'},
{ 'doctype': 'Domain', 'domain': 'Retail'},
{ 'doctype': 'Domain', 'domain': 'Services'},
{ 'doctype': 'Domain', 'domain': 'Education'},
{ 'doctype': 'Domain', 'domain': 'Healthcare'},
# Setup Progress
{'doctype': "Setup Progress", "actions": [

View File

@@ -40,7 +40,7 @@ def setup_complete(args=None):
frappe.local.message_log = []
domain_settings = frappe.get_single('Domain Settings')
domain_settings.set_active_domains([_(args.get('domain'))])
domain_settings.set_active_domains([args.get('domain')])
frappe.db.commit()
login_as_first_user(args)
@@ -186,10 +186,6 @@ def set_defaults(args):
hr_settings.emp_created_by = "Naming Series"
hr_settings.save()
domain_settings = frappe.get_doc("Domain Settings")
domain_settings.append('active_domains', dict(domain=_(args.get('domain'))))
domain_settings.save()
def create_feed_and_todo():
"""update Activity feed and create todo for creation of item, customer, vendor"""
add_info_comment(**{

View File

@@ -65,31 +65,38 @@ frappe.ui.form.on('Batch', {
// move - ask for target warehouse and make stock entry
rows.find('.btn-move').on('click', function() {
var $btn = $(this);
frappe.prompt({
fieldname: 'to_warehouse',
label: __('To Warehouse'),
fieldtype: 'Link',
options: 'Warehouse'
},
(data) => {
frappe.call({
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
args: {
item_code: frm.doc.item,
batch_no: frm.doc.name,
qty: $btn.attr('data-qty'),
from_warehouse: $btn.attr('data-warehouse'),
to_warehouse: data.to_warehouse
},
callback: (r) => {
frappe.show_alert(__('Stock Entry {0} created',
['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
frm.refresh();
},
});
},
__('Select Target Warehouse'),
__('Move')
const fields = [
{
fieldname: 'to_warehouse',
label: __('To Warehouse'),
fieldtype: 'Link',
options: 'Warehouse'
}
];
frappe.prompt(
fields,
(data) => {
frappe.call({
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
args: {
item_code: frm.doc.item,
batch_no: frm.doc.name,
qty: $btn.attr('data-qty'),
from_warehouse: $btn.attr('data-warehouse'),
to_warehouse: data.to_warehouse,
source_document: frm.doc.reference_name,
reference_doctype: frm.doc.reference_doctype
},
callback: (r) => {
frappe.show_alert(__('Stock Entry {0} created',
['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
frm.refresh();
},
});
},
__('Select Target Warehouse'),
__('Move')
);
});

View File

@@ -90,7 +90,7 @@ class Bin(Document):
self.set_projected_qty()
self.db_set('reserved_qty_for_production', self.reserved_qty_for_production)
self.db_set('reserved_qty_for_production', flt(self.reserved_qty_for_production))
self.db_set('projected_qty', self.projected_qty)

View File

@@ -12,6 +12,7 @@ from erpnext import set_perpetual_inventory
from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError
from erpnext.accounts.doctype.account.test_account import get_inventory_account
class TestPurchaseReceipt(unittest.TestCase):
def setUp(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
@@ -259,7 +260,7 @@ class TestPurchaseReceipt(unittest.TestCase):
item_code = frappe.db.get_value('Item', {'has_serial_no': 1})
if not item_code:
item = make_item("Test Serial Item 1", dict(has_serial_no = 1))
item = make_item("Test Serial Item 1", dict(has_serial_no=1))
item_code = item.name
serial_no = random_string(5)
@@ -273,11 +274,13 @@ class TestPurchaseReceipt(unittest.TestCase):
serial_no=serial_no, basic_rate=100, do_not_submit=True)
self.assertRaises(SerialNoDuplicateError, se.submit)
def get_gl_entries(voucher_type, voucher_no):
return frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account desc""", (voucher_type, voucher_no), as_dict=1)
def make_purchase_receipt(**args):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
pr = frappe.new_doc("Purchase Receipt")

View File

@@ -14,8 +14,6 @@ frappe.ui.form.on('Stock Entry', {
]
}
});
// },
// onload_post_render: function(frm) {
frm.set_query('batch_no', 'items', function(doc, cdt, cdn) {
var item = locals[cdt][cdn];
@@ -40,9 +38,8 @@ frappe.ui.form.on('Stock Entry', {
}
}
});
},
refresh: function(frm) {
if(!frm.doc.docstatus) {
frm.add_custom_button(__('Make Material Request'), function() {
@@ -73,10 +70,12 @@ frappe.ui.form.on('Stock Entry', {
frm.trigger("toggle_display_account_head");
}
},
purpose: function(frm) {
frm.fields_dict.items.grid.refresh();
frm.cscript.toggle_related_fields(frm.doc);
},
company: function(frm) {
if(frm.doc.company) {
var company_doc = frappe.get_doc(":Company", frm.doc.company);
@@ -86,6 +85,7 @@ frappe.ui.form.on('Stock Entry', {
frm.trigger("toggle_display_account_head");
}
},
set_serial_no: function(frm, cdt, cdn) {
var d = frappe.model.get_doc(cdt, cdn);
if(!d.item_code && !d.s_warehouse && !d.qty) return;
@@ -104,20 +104,142 @@ frappe.ui.form.on('Stock Entry', {
}
});
},
toggle_display_account_head: function(frm) {
var enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company);
frm.fields_dict["items"].grid.set_column_disp(["cost_center", "expense_account"], enabled);
}
},
set_basic_rate: function(frm, cdt, cdn, callback) {
const item = locals[cdt][cdn];
item.transfer_qty = flt(item.qty) * flt(item.conversion_factor);
const args = {
'item_code' : item.item_code,
'posting_date' : frm.doc.posting_date,
'posting_time' : frm.doc.posting_time,
'warehouse' : cstr(item.s_warehouse) || cstr(item.t_warehouse),
'serial_no ' : item.serial_no,
'company' : frm.doc.company,
'qty' : item.s_warehouse ? -1*flt(item.transfer_qty) : flt(item.transfer_qty)
};
frappe.call({
method: "erpnext.stock.utils.get_incoming_rate",
args: {
args: args
},
callback: function(r) {
frappe.model.set_value(cdt, cdn, 'basic_rate', r.message);
frm.events.calculate_basic_amount(frm, item);
if (callback) {
callback();
}
}
})
},
get_warehouse_details: function(frm, cdt, cdn, callback) {
var child = locals[cdt][cdn];
if(!child.bom_no) {
frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_warehouse_details",
args: {
"args": {
'item_code': child.item_code,
'warehouse': cstr(child.s_warehouse) || cstr(child.t_warehouse),
'transfer_qty': child.transfer_qty,
'serial_no': child.serial_no,
'qty': child.s_warehouse ? -1* child.transfer_qty : child.transfer_qty,
'posting_date': frm.doc.posting_date,
'posting_time': frm.doc.posting_time
}
},
callback: function(r) {
if (!r.exc) {
$.extend(child, r.message);
frm.events.calculate_basic_amount(frm, child);
}
if (callback) {
callback();
}
}
});
}
},
calculate_basic_amount: function(frm, item) {
item.basic_amount = flt(flt(item.transfer_qty) * flt(item.basic_rate),
precision("basic_amount", item));
frm.events.calculate_amount(frm);
},
calculate_amount: function(frm) {
frm.events.calculate_total_additional_costs(frm);
const total_basic_amount = frappe.utils.sum(
(frm.doc.items || []).map(function(i) { return i.t_warehouse ? flt(i.basic_amount) : 0; })
);
for (let i in frm.doc.items) {
let item = frm.doc.items[i];
if (item.t_warehouse && total_basic_amount) {
item.additional_cost = (flt(item.basic_amount) / total_basic_amount) * frm.doc.total_additional_costs;
} else {
item.additional_cost = 0;
}
item.amount = flt(item.basic_amount + flt(item.additional_cost),
precision("amount", item));
item.valuation_rate = flt(flt(item.basic_rate)
+ (flt(item.additional_cost) / flt(item.transfer_qty)),
precision("valuation_rate", item));
}
refresh_field('items');
},
calculate_total_additional_costs: function(frm) {
const total_additional_costs = frappe.utils.sum(
(frm.doc.additional_costs || []).map(function(c) { return flt(c.amount); })
);
frm.set_value("total_additional_costs",
flt(total_additional_costs, precision("total_additional_costs")));
},
})
frappe.ui.form.on('Stock Entry Detail', {
qty: function(frm, cdt, cdn) {
frm.events.set_serial_no(frm, cdt, cdn);
frm.events.set_basic_rate(frm, cdt, cdn, () => {
frm.events.set_serial_no(frm, cdt, cdn);
});
},
conversion_factor: function(frm, cdt, cdn) {
frm.events.set_basic_rate(frm, cdt, cdn);
},
s_warehouse: function(frm, cdt, cdn) {
frm.events.set_serial_no(frm, cdt, cdn);
frm.events.get_warehouse_details(frm, cdt, cdn, () => {
frm.events.set_serial_no(frm, cdt, cdn);
});
},
t_warehouse: function(frm, cdt, cdn) {
frm.events.get_warehouse_details(frm, cdt, cdn);
},
basic_rate: function(frm, cdt, cdn) {
var item = locals[cdt][cdn];
frm.events.calculate_basic_amount(frm, item);
},
barcode: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if (d.barcode) {
@@ -132,6 +254,7 @@ frappe.ui.form.on('Stock Entry Detail', {
});
}
},
uom: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.uom && d.item_code){
@@ -150,6 +273,7 @@ frappe.ui.form.on('Stock Entry Detail', {
});
}
},
item_code: function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.item_code) {
@@ -157,7 +281,7 @@ frappe.ui.form.on('Stock Entry Detail', {
'item_code' : d.item_code,
'warehouse' : cstr(d.s_warehouse) || cstr(d.t_warehouse),
'transfer_qty' : d.transfer_qty,
'serial_no ' : d.serial_no,
'serial_no' : d.serial_no,
'bom_no' : d.bom_no,
'expense_account' : d.expense_account,
'cost_center' : d.cost_center,
@@ -191,7 +315,7 @@ frappe.ui.form.on('Stock Entry Detail', {
frappe.ui.form.on('Landed Cost Taxes and Charges', {
amount: function(frm) {
frm.events.calculate_amount();
frm.events.calculate_amount(frm);
}
});
@@ -330,12 +454,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}
},
qty: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
d.transfer_qty = flt(d.qty) * flt(d.conversion_factor);
this.calculate_basic_amount(d);
},
production_order: function() {
var me = this;
this.toggle_enable_bom();
@@ -434,88 +552,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
erpnext.setup_serial_no();
},
basic_rate: function(doc, cdt, cdn) {
var item = frappe.model.get_doc(cdt, cdn);
this.calculate_basic_amount(item);
},
s_warehouse: function(doc, cdt, cdn) {
this.get_warehouse_details(doc, cdt, cdn)
},
t_warehouse: function(doc, cdt, cdn) {
this.get_warehouse_details(doc, cdt, cdn)
},
get_warehouse_details: function(doc, cdt, cdn) {
var me = this;
var d = locals[cdt][cdn];
if(!d.bom_no) {
frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_warehouse_details",
args: {
"args": {
'item_code': d.item_code,
'warehouse': cstr(d.s_warehouse) || cstr(d.t_warehouse),
'transfer_qty': d.transfer_qty,
'serial_no': d.serial_no,
'qty': d.s_warehouse ? -1* d.qty : d.qty,
'posting_date': this.frm.doc.posting_date,
'posting_time': this.frm.doc.posting_time
}
},
callback: function(r) {
if (!r.exc) {
$.extend(d, r.message);
me.calculate_basic_amount(d);
}
}
});
}
},
calculate_basic_amount: function(item) {
item.basic_amount = flt(flt(item.transfer_qty) * flt(item.basic_rate),
precision("basic_amount", item));
this.calculate_amount();
},
calculate_amount: function() {
this.calculate_total_additional_costs();
var total_basic_amount = frappe.utils.sum(
(this.frm.doc.items || []).map(function(i) { return i.t_warehouse ? flt(i.basic_amount) : 0; })
);
for (var i in this.frm.doc.items) {
var item = this.frm.doc.items[i];
if (item.t_warehouse && total_basic_amount) {
item.additional_cost = (flt(item.basic_amount) / total_basic_amount) * this.frm.doc.total_additional_costs;
} else {
item.additional_cost = 0;
}
item.amount = flt(item.basic_amount + flt(item.additional_cost),
precision("amount", item));
item.valuation_rate = flt(flt(item.basic_rate)
+ (flt(item.additional_cost) / flt(item.transfer_qty)),
precision("valuation_rate", item));
}
refresh_field('items');
},
calculate_total_additional_costs: function() {
var total_additional_costs = frappe.utils.sum(
(this.frm.doc.additional_costs || []).map(function(c) { return flt(c.amount); })
);
this.frm.set_value("total_additional_costs", flt(total_additional_costs, precision("total_additional_costs")));
},
toggle_related_fields: function(doc) {
this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');

View File

@@ -49,6 +49,9 @@ class StockEntry(StockController):
self.validate_with_material_request()
self.validate_batch()
if not self.from_bom:
self.fg_completed_qty = 0.0
if self._action == 'submit':
self.make_batches('t_warehouse')
else:
@@ -351,6 +354,7 @@ class StockEntry(StockController):
if self.purpose == "Subcontract" and self.purchase_order:
purchase_order = frappe.get_doc("Purchase Order", self.purchase_order)
for se_item in self.items:
precision = cint(frappe.db.get_default("float_precision")) or 3
total_allowed = sum([flt(d.required_qty) for d in purchase_order.supplied_items \
if d.rm_item_code == se_item.item_code])
if not total_allowed:
@@ -364,8 +368,8 @@ class StockEntry(StockController):
and `tabStock Entry Detail`.parent = `tabStock Entry`.name""",
(self.purchase_order, se_item.item_code))[0][0]
if total_supplied > total_allowed:
frappe.throw(_("Not allowed to tranfer more {0} than {1} against Purchase Order {2}").format(se_item.item_code,
if flt(total_supplied, precision) > flt(total_allowed, precision):
frappe.throw(_("Not allowed to transfer more {0} than {1} against Purchase Order {2}").format(se_item.item_code,
total_allowed, self.purchase_order))
def validate_bom(self):
@@ -517,7 +521,7 @@ class StockEntry(StockController):
args['posting_date'] = self.posting_date
args['posting_time'] = self.posting_time
stock_and_rate = args.get('warehouse') and get_warehouse_details(args) or {}
stock_and_rate = get_warehouse_details(args) if args.get('warehouse') else {}
ret.update(stock_and_rate)
# automatically select batch for outgoing item
@@ -771,6 +775,9 @@ class StockEntry(StockController):
se_child.expense_account = item_dict[d].get("expense_account") or expense_account
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
if item_dict[d].get("idx"):
se_child.idx = item_dict[d].get("idx")
if se_child.s_warehouse==None:
se_child.s_warehouse = self.from_warehouse
if se_child.t_warehouse==None:

View File

@@ -20,6 +20,16 @@ def make_stock_entry(**args):
:do_not_save: Optional flag
:do_not_submit: Optional flag
'''
def process_serial_numbers(serial_nos_list):
serial_nos_list = [
'\n'.join(serial_num['serial_no'] for serial_num in serial_nos_list)
]
uniques = list(set(serial_nos_list[0].split('\n')))
return '\n'.join(uniques)
s = frappe.new_doc("Stock Entry")
args = frappe._dict(args)
@@ -77,6 +87,25 @@ def make_stock_entry(**args):
if not args.cost_center:
args.cost_center = frappe.get_value('Company', s.company, 'cost_center')
if not args.expense_account:
args.expense_account = frappe.get_value('Company', s.company, 'stock_adjustment_account')
# We can find out the serial number using the batch source document
serial_number = args.serial_no
if not args.serial_no and args.qty and args.batch_no:
serial_number_list = frappe.get_list(
doctype='Stock Ledger Entry',
fields=['serial_no'],
filters={
'batch_no': args.batch_no,
'warehouse': args.from_warehouse
}
)
serial_number = process_serial_numbers(serial_number_list)
args.serial_no = serial_number
s.append("items", {
"item_code": args.item,
"s_warehouse": args.source,

View File

@@ -96,16 +96,6 @@ def get_item_details(args):
return out
# print(frappe._dict({
# 'has_serial_no' : out.has_serial_no,
# 'has_batch_no' : out.has_batch_no
# }))
# return frappe._dict({
# 'has_serial_no' : out.has_serial_no,
# 'has_batch_no' : out.has_batch_no
# })
def process_args(args):
if isinstance(args, basestring):
args = json.loads(args)
@@ -373,11 +363,11 @@ def get_pos_profile_item_details(company, args, pos_profile=None):
@frappe.whitelist()
def get_pos_profile(company):
pos_profile = frappe.db.sql("""select * from `tabPOS Profile` where user = %s
and company = %s""", (frappe.session['user'], company), as_dict=1)
and company = %s and ifnull(disabled,0) != 1""", (frappe.session['user'], company), as_dict=1)
if not pos_profile:
pos_profile = frappe.db.sql("""select * from `tabPOS Profile`
where ifnull(user,'') = '' and company = %s""", company, as_dict=1)
where ifnull(user,'') = '' and company = %s and ifnull(disabled,0) != 1""", company, as_dict=1)
return pos_profile and pos_profile[0] or None
@@ -532,8 +522,6 @@ def get_default_bom(item_code=None):
bom = frappe.db.get_value("BOM", {"docstatus": 1, "is_default": 1, "is_active": 1, "item": item_code})
if bom:
return bom
else:
frappe.throw(_("No default BOM exists for Item {0}").format(item_code))
def get_valuation_rate(item_code, warehouse=None):
item = frappe.get_doc("Item", item_code)

View File

@@ -230,6 +230,13 @@ class update_entries_after(object):
# else it remains the same as that of previous entry
self.valuation_rate = new_stock_value / new_stock_qty
if not self.valuation_rate and sle.voucher_detail_no:
allow_zero_rate = self.check_if_allow_zero_valuation_rate(sle.voucher_type, sle.voucher_detail_no)
if not allow_zero_rate:
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
currency=erpnext.get_company_currency(sle.company))
def get_moving_average_values(self, sle):
actual_qty = flt(sle.actual_qty)
new_stock_qty = flt(self.qty_after_transaction) + actual_qty

View File

@@ -126,7 +126,7 @@ def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False):
def get_incoming_rate(args):
"""Get Incoming Rate based on valuation method"""
from erpnext.stock.stock_ledger import get_previous_sle
if isinstance(args, basestring):
args = json.loads(args)
@@ -141,6 +141,8 @@ def get_incoming_rate(args):
return 0.0
previous_stock_queue = json.loads(previous_sle.get('stock_queue', '[]') or '[]')
in_rate = get_fifo_rate(previous_stock_queue, args.get("qty") or 0) if previous_stock_queue else 0
if not in_rate and not previous_stock_queue:
in_rate = previous_sle.get('valuation_rate') or 0
elif valuation_method == 'Moving Average':
in_rate = previous_sle.get('valuation_rate') or 0