Merge branch 'develop' into naming-series-proj

This commit is contained in:
Marica 2020-11-16 13:32:24 +05:30 committed by GitHub
commit 06f522cb27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 570 additions and 489 deletions

View File

@ -23,7 +23,7 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Reports", "label": "Reports",
"links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"Trial Balance for Party\",\n \"name\": \"Trial Balance for Party\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Journal Entry\"\n ],\n \"doctype\": \"Journal Entry\",\n \"is_query_report\": true,\n \"label\": \"Payment Period Based On Invoice Date\",\n \"name\": \"Payment Period Based On Invoice Date\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Payment Summary\",\n \"name\": \"Sales Payment Summary\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Address And Contacts\",\n \"name\": \"Address And Contacts\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"GL Entry\"\n ],\n \"doctype\": \"GL Entry\",\n \"is_query_report\": true,\n \"label\": \"DATEV Export\",\n \"name\": \"DATEV\",\n \"type\": \"report\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -98,7 +98,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Accounting", "label": "Accounting",
"modified": "2020-11-06 13:05:58.650150", "modified": "2020-11-11 18:35:11.542909",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounting", "name": "Accounting",

View File

@ -9,11 +9,7 @@ frappe.ui.form.on('Fiscal Year', {
} }
}, },
refresh: function (frm) { refresh: function (frm) {
let doc = frm.doc; if (!frm.doc.__islocal && (frm.doc.name != frappe.sys_defaults.fiscal_year)) {
frm.toggle_enable('year_start_date', doc.__islocal);
frm.toggle_enable('year_end_date', doc.__islocal);
if (!doc.__islocal && (doc.name != frappe.sys_defaults.fiscal_year)) {
frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm)); frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'")); frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
} else { } else {
@ -24,8 +20,10 @@ frappe.ui.form.on('Fiscal Year', {
return frm.call('set_as_default'); return frm.call('set_as_default');
}, },
year_start_date: function(frm) { year_start_date: function(frm) {
let year_end_date = if (!frm.doc.is_short_year) {
frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1); let year_end_date =
frm.set_value("year_end_date", year_end_date); frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
frm.set_value("year_end_date", year_end_date);
}
}, },
}); });

View File

@ -1,347 +1,126 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0,
"autoname": "field:year", "autoname": "field:year",
"beta": 0,
"creation": "2013-01-22 16:50:25", "creation": "2013-01-22 16:50:25",
"custom": 0,
"description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.", "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup", "document_type": "Setup",
"editable_grid": 0, "engine": "InnoDB",
"field_order": [
"year",
"disabled",
"is_short_year",
"year_start_date",
"year_end_date",
"companies",
"auto_created"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "For e.g. 2012, 2012-13", "description": "For e.g. 2012, 2012-13",
"fieldname": "year", "fieldname": "year",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Year Name", "label": "Year Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "year", "oldfieldname": "year",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "unique": 1
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "label": "Disabled"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Disabled",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "year_start_date", "fieldname": "year_start_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Year Start Date", "label": "Year Start Date",
"length": 0,
"no_copy": 1, "no_copy": 1,
"oldfieldname": "year_start_date", "oldfieldname": "year_start_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "set_only_once": 1
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "year_end_date", "fieldname": "year_end_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Year End Date", "label": "Year End Date",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "set_only_once": 1
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "companies", "fieldname": "companies",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Companies", "label": "Companies",
"length": 0, "options": "Fiscal Year Company"
"no_copy": 0,
"options": "Fiscal Year Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0", "default": "0",
"fieldname": "auto_created", "fieldname": "auto_created",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "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": "Auto Created", "label": "Auto Created",
"length": 0,
"no_copy": 1, "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "read_only": 1
"read_only": 1, },
"remember_last_selected_value": 0, {
"report_hide": 0, "default": "0",
"reqd": 0, "description": "Less than 12 months.",
"search_index": 0, "fieldname": "is_short_year",
"set_only_once": 0, "fieldtype": "Check",
"translatable": 0, "label": "Is Short Year",
"unique": 0 "set_only_once": 1
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-calendar", "icon": "fa fa-calendar",
"idx": 1, "idx": 1,
"image_view": 0, "links": [],
"in_create": 0, "modified": "2020-11-05 12:16:53.081573",
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-04-25 14:21:41.273354",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Fiscal Year", "name": "Fiscal Year",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "System Manager", "role": "System Manager",
"set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 0, "role": "Sales User"
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 0, "role": "Purchase User"
"role": "Purchase User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 0, "role": "Accounts User"
"role": "Accounts User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 0, "role": "Stock User"
"role": "Stock User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 0, "role": "Employee"
"role": "Employee",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
} }
], ],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1, "show_name_in_global_search": 1,
"sort_field": "name", "sort_field": "name",
"sort_order": "DESC", "sort_order": "DESC"
"track_changes": 0,
"track_seen": 0
} }

View File

@ -36,6 +36,11 @@ class FiscalYear(Document):
frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved.")) frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."))
def validate_dates(self): def validate_dates(self):
if self.is_short_year:
# Fiscal Year can be shorter than one year, in some jurisdictions
# under certain circumstances. For example, in the USA and Germany.
return
if getdate(self.year_start_date) > getdate(self.year_end_date): if getdate(self.year_start_date) > getdate(self.year_end_date):
frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"), frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"),
FiscalYearIncorrectDate) FiscalYearIncorrectDate)
@ -116,12 +121,8 @@ def auto_create_fiscal_year():
pass pass
def get_from_and_to_date(fiscal_year): def get_from_and_to_date(fiscal_year):
from_and_to_date_tuple = frappe.db.sql("""select year_start_date, year_end_date fields = [
from `tabFiscal Year` where name=%s""", (fiscal_year))[0] "year_start_date as from_date",
"year_end_date as to_date"
from_and_to_date = { ]
"from_date": from_and_to_date_tuple[0], return frappe.db.get_value("Fiscal Year", fiscal_year, fields, as_dict=1)
"to_date": from_and_to_date_tuple[1]
}
return from_and_to_date

View File

@ -11,6 +11,7 @@ test_records = frappe.get_test_records('Fiscal Year')
test_ignore = ["Company"] test_ignore = ["Company"]
class TestFiscalYear(unittest.TestCase): class TestFiscalYear(unittest.TestCase):
def test_extra_year(self): def test_extra_year(self):
if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"): if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000") frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")

View File

@ -1,4 +1,11 @@
[ [
{
"doctype": "Fiscal Year",
"year": "_Test Short Fiscal Year 2011",
"is_short_year": 1,
"year_end_date": "2011-04-01",
"year_start_date": "2011-12-31"
},
{ {
"doctype": "Fiscal Year", "doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2012", "year": "_Test Fiscal Year 2012",

View File

@ -352,8 +352,14 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
pricing_rule_rate = 0.0 pricing_rule_rate = 0.0
if pricing_rule.currency == args.currency: if pricing_rule.currency == args.currency:
pricing_rule_rate = pricing_rule.rate pricing_rule_rate = pricing_rule.rate
if pricing_rule_rate:
# Override already set price list rate (from item price)
# if pricing_rule_rate > 0
item_details.update({
"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
})
item_details.update({ item_details.update({
"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
"discount_percentage": 0.0 "discount_percentage": 0.0
}) })

View File

@ -484,6 +484,43 @@ class TestPricingRule(unittest.TestCase):
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
def test_item_price_with_pricing_rule(self):
item = make_item("Water Flask")
make_item_price("Water Flask", "_Test Price List", 100)
pricing_rule_record = {
"doctype": "Pricing Rule",
"title": "_Test Water Flask Rule",
"apply_on": "Item Code",
"items": [{
"item_code": "Water Flask",
}],
"selling": 1,
"currency": "INR",
"rate_or_discount": "Rate",
"rate": 0,
"margin_type": "Percentage",
"margin_rate_or_amount": 2,
"company": "_Test Company"
}
rule = frappe.get_doc(pricing_rule_record)
rule.insert()
si = create_sales_invoice(do_not_save=True, item_code="Water Flask")
si.selling_price_list = "_Test Price List"
si.save()
# If rate in Rule is 0, give preference to Item Price if it exists
self.assertEqual(si.items[0].price_list_rate, 100)
self.assertEqual(si.items[0].margin_rate_or_amount, 2)
self.assertEqual(si.items[0].rate_with_margin, 102)
self.assertEqual(si.items[0].rate, 102)
si.delete()
rule.delete()
frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
item.delete()
def make_pricing_rule(**args): def make_pricing_rule(**args):
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -90,6 +90,11 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship); this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
if(doc.docstatus == 1) { if(doc.docstatus == 1) {
this.frm.fields_dict.items_section.wrapper.addClass("hide-border");
if(!this.frm.doc.set_warehouse) {
this.frm.fields_dict.items_section.wrapper.removeClass("hide-border");
}
if(!in_list(["Closed", "Delivered"], doc.status)) { if(!in_list(["Closed", "Delivered"], doc.status)) {
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) { if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
this.frm.add_custom_button(__('Update Items'), () => { this.frm.add_custom_button(__('Update Items'), () => {
@ -126,16 +131,25 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
if(doc.status != "Closed") { if(doc.status != "Closed") {
if (doc.status != "On Hold") { if (doc.status != "On Hold") {
if(flt(doc.per_received) < 100 && allow_receipt) { if(flt(doc.per_received) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create')); cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) { if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
cur_frm.add_custom_button(__('Material to Supplier'), cur_frm.add_custom_button(__('Material to Supplier'),
function() { me.make_stock_entry(); }, __("Transfer")); function() { me.make_stock_entry(); }, __("Transfer"));
} }
} }
if(flt(doc.per_billed) < 100) if(flt(doc.per_billed) < 100)
cur_frm.add_custom_button(__('Invoice'), cur_frm.add_custom_button(__('Purchase Invoice'),
this.make_purchase_invoice, __('Create')); this.make_purchase_invoice, __('Create'));
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
}
if(flt(doc.per_billed)==0) {
this.frm.add_custom_button(__('Payment Request'),
function() { me.make_payment_request() }, __('Create'));
}
if(!doc.auto_repeat) { if(!doc.auto_repeat) {
cur_frm.add_custom_button(__('Subscription'), function() { cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name) erpnext.utils.make_subscription(doc.doctype, doc.name)
@ -156,13 +170,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
}); });
} }
} }
if(flt(doc.per_billed)==0) {
this.frm.add_custom_button(__('Payment Request'),
function() { me.make_payment_request() }, __('Create'));
}
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
}
cur_frm.page.set_inner_btn_group_as_primary(__('Create')); cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
} }
} else if(doc.docstatus===0) { } else if(doc.docstatus===0) {
@ -358,12 +366,16 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order", method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request", source_doctype: "Material Request",
target: me.frm, target: me.frm,
setters: {}, setters: {
schedule_date: undefined,
status: undefined
},
get_query_filters: { get_query_filters: {
material_request_type: "Purchase", material_request_type: "Purchase",
docstatus: 1, docstatus: 1,
status: ["!=", "Stopped"], status: ["!=", "Stopped"],
per_ordered: ["<", 99.99], per_ordered: ["<", 99.99],
company: me.frm.doc.company
} }
}) })
}, __("Get Items From")); }, __("Get Items From"));
@ -375,16 +387,17 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
source_doctype: "Supplier Quotation", source_doctype: "Supplier Quotation",
target: me.frm, target: me.frm,
setters: { setters: {
supplier: me.frm.doc.supplier supplier: me.frm.doc.supplier,
valid_till: undefined
}, },
get_query_filters: { get_query_filters: {
docstatus: 1, docstatus: 1,
status: ["!=", "Stopped"], status: ["not in", ["Stopped", "Expired"]],
} }
}) })
}, __("Get Items From")); }, __("Get Items From"));
this.frm.add_custom_button(__('Update rate as per last purchase'), this.frm.add_custom_button(__('Update Rate as per Last Purchase'),
function() { function() {
frappe.call({ frappe.call({
"method": "get_last_purchase_rate", "method": "get_last_purchase_rate",

View File

@ -30,8 +30,8 @@
"customer_contact_email", "customer_contact_email",
"section_addresses", "section_addresses",
"supplier_address", "supplier_address",
"contact_person",
"address_display", "address_display",
"contact_person",
"contact_display", "contact_display",
"contact_mobile", "contact_mobile",
"contact_email", "contact_email",
@ -49,12 +49,14 @@
"plc_conversion_rate", "plc_conversion_rate",
"ignore_pricing_rule", "ignore_pricing_rule",
"sec_warehouse", "sec_warehouse",
"set_warehouse",
"col_break_warehouse",
"is_subcontracted", "is_subcontracted",
"col_break_warehouse",
"supplier_warehouse", "supplier_warehouse",
"items_section", "before_items_section",
"scan_barcode", "scan_barcode",
"items_col_break",
"set_warehouse",
"items_section",
"items", "items",
"sb_last_purchase", "sb_last_purchase",
"total_qty", "total_qty",
@ -108,18 +110,13 @@
"payment_terms_template", "payment_terms_template",
"payment_schedule", "payment_schedule",
"tracking_section", "tracking_section",
"per_billed", "status",
"column_break_75", "column_break_75",
"per_billed",
"per_received", "per_received",
"terms_section_break", "terms_section_break",
"tc_name", "tc_name",
"terms", "terms",
"more_info",
"status",
"ref_sq",
"column_break_74",
"party_account_currency",
"inter_company_order_reference",
"column_break5", "column_break5",
"letter_head", "letter_head",
"select_print_heading", "select_print_heading",
@ -131,7 +128,12 @@
"to_date", "to_date",
"column_break_97", "column_break_97",
"auto_repeat", "auto_repeat",
"update_auto_repeat_reference" "update_auto_repeat_reference",
"more_info",
"ref_sq",
"column_break_74",
"party_account_currency",
"inter_company_order_reference"
], ],
"fields": [ "fields": [
{ {
@ -313,34 +315,34 @@
{ {
"fieldname": "supplier_address", "fieldname": "supplier_address",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Select Supplier Address", "label": "Supplier Address",
"options": "Address", "options": "Address",
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "contact_person", "fieldname": "contact_person",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Contact Person", "label": "Supplier Contact",
"options": "Contact", "options": "Contact",
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "address_display", "fieldname": "address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"label": "Address", "label": "Supplier Address Details",
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "contact_display", "fieldname": "contact_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"in_global_search": 1, "in_global_search": 1,
"label": "Contact", "label": "Contact Name",
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "contact_mobile", "fieldname": "contact_mobile",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"label": "Mobile No", "label": "Contact Mobile No",
"read_only": 1 "read_only": 1
}, },
{ {
@ -358,14 +360,14 @@
{ {
"fieldname": "shipping_address", "fieldname": "shipping_address",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Select Shipping Address", "label": "Company Shipping Address",
"options": "Address", "options": "Address",
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "shipping_address_display", "fieldname": "shipping_address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"label": "Shipping Address", "label": "Shipping Address Details",
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
@ -433,7 +435,8 @@
}, },
{ {
"fieldname": "sec_warehouse", "fieldname": "sec_warehouse",
"fieldtype": "Section Break" "fieldtype": "Section Break",
"label": "Subcontracting"
}, },
{ {
"description": "Sets 'Warehouse' in each row of the Items table.", "description": "Sets 'Warehouse' in each row of the Items table.",
@ -466,6 +469,7 @@
{ {
"fieldname": "items_section", "fieldname": "items_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hide_border": 1,
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart" "options": "fa fa-shopping-cart"
}, },
@ -598,7 +602,8 @@
}, },
{ {
"fieldname": "section_break_52", "fieldname": "section_break_52",
"fieldtype": "Section Break" "fieldtype": "Section Break",
"hide_border": 1
}, },
{ {
"fieldname": "taxes", "fieldname": "taxes",
@ -626,10 +631,12 @@
{ {
"fieldname": "totals", "fieldname": "totals",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Taxes and Charges",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "fa fa-money" "options": "fa fa-money"
}, },
{ {
"depends_on": "base_taxes_and_charges_added",
"fieldname": "base_taxes_and_charges_added", "fieldname": "base_taxes_and_charges_added",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Taxes and Charges Added (Company Currency)", "label": "Taxes and Charges Added (Company Currency)",
@ -640,6 +647,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "base_taxes_and_charges_deducted",
"fieldname": "base_taxes_and_charges_deducted", "fieldname": "base_taxes_and_charges_deducted",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Taxes and Charges Deducted (Company Currency)", "label": "Taxes and Charges Deducted (Company Currency)",
@ -650,6 +658,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "base_total_taxes_and_charges",
"fieldname": "base_total_taxes_and_charges", "fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Total Taxes and Charges (Company Currency)", "label": "Total Taxes and Charges (Company Currency)",
@ -665,6 +674,7 @@
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"depends_on": "taxes_and_charges_added",
"fieldname": "taxes_and_charges_added", "fieldname": "taxes_and_charges_added",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Taxes and Charges Added", "label": "Taxes and Charges Added",
@ -675,6 +685,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "taxes_and_charges_deducted",
"fieldname": "taxes_and_charges_deducted", "fieldname": "taxes_and_charges_deducted",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Taxes and Charges Deducted", "label": "Taxes and Charges Deducted",
@ -685,6 +696,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "total_taxes_and_charges",
"fieldname": "total_taxes_and_charges", "fieldname": "total_taxes_and_charges",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Total Taxes and Charges", "label": "Total Taxes and Charges",
@ -694,7 +706,7 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "discount_amount", "collapsible_depends_on": "apply_discount_on",
"fieldname": "discount_section", "fieldname": "discount_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Additional Discount" "label": "Additional Discount"
@ -734,7 +746,8 @@
}, },
{ {
"fieldname": "totals_section", "fieldname": "totals_section",
"fieldtype": "Section Break" "fieldtype": "Section Break",
"label": "Totals"
}, },
{ {
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
@ -902,12 +915,12 @@
}, },
{ {
"fieldname": "ref_sq", "fieldname": "ref_sq",
"fieldtype": "Data", "fieldtype": "Link",
"hidden": 1, "label": "Supplier Quotation",
"label": "Ref SQ",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "ref_sq", "oldfieldname": "ref_sq",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "Supplier Quotation",
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
@ -1061,7 +1074,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "tracking_section", "fieldname": "tracking_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Tracking" "label": "Order Status"
}, },
{ {
"fieldname": "column_break_75", "fieldname": "column_break_75",
@ -1070,21 +1083,29 @@
{ {
"fieldname": "billing_address", "fieldname": "billing_address",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Select Billing Address", "label": "Company Billing Address",
"options": "Address" "options": "Address"
}, },
{ {
"fieldname": "billing_address_display", "fieldname": "billing_address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"label": "Billing Address", "label": "Billing Address Details",
"read_only": 1 "read_only": 1
},
{
"fieldname": "before_items_section",
"fieldtype": "Section Break"
},
{
"fieldname": "items_col_break",
"fieldtype": "Column Break"
} }
], ],
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-10-07 14:31:57.661221", "modified": "2020-10-30 11:39:37.388249",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@ -24,6 +24,7 @@
"col_break2", "col_break2",
"uom", "uom",
"conversion_factor", "conversion_factor",
"stock_qty",
"sec_break1", "sec_break1",
"price_list_rate", "price_list_rate",
"discount_percentage", "discount_percentage",
@ -46,11 +47,8 @@
"column_break_32", "column_break_32",
"base_net_rate", "base_net_rate",
"base_net_amount", "base_net_amount",
"billed_amt",
"warehouse_and_reference", "warehouse_and_reference",
"warehouse", "warehouse",
"delivered_by_supplier",
"project",
"material_request", "material_request",
"material_request_item", "material_request_item",
"sales_order", "sales_order",
@ -58,36 +56,37 @@
"supplier_quotation", "supplier_quotation",
"supplier_quotation_item", "supplier_quotation_item",
"col_break5", "col_break5",
"delivered_by_supplier",
"against_blanket_order", "against_blanket_order",
"blanket_order", "blanket_order",
"blanket_order_rate", "blanket_order_rate",
"item_group", "item_group",
"brand", "brand",
"bom",
"include_exploded_items",
"section_break_56", "section_break_56",
"stock_qty",
"column_break_60",
"received_qty", "received_qty",
"returned_qty", "returned_qty",
"manufacture_details", "column_break_60",
"manufacturer", "billed_amt",
"column_break_14",
"manufacturer_part_no",
"more_info_section_break",
"is_fixed_asset",
"item_tax_rate",
"accounting_details", "accounting_details",
"expense_account", "expense_account",
"column_break_68", "manufacture_details",
"manufacturer",
"manufacturer_part_no",
"column_break_14",
"bom",
"include_exploded_items",
"item_weight_details", "item_weight_details",
"weight_per_unit", "weight_per_unit",
"total_weight", "total_weight",
"column_break_40", "column_break_40",
"weight_uom", "weight_uom",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "project",
"dimension_col_break", "dimension_col_break",
"cost_center",
"more_info_section_break",
"is_fixed_asset",
"item_tax_rate",
"section_break_72", "section_break_72",
"page_break" "page_break"
], ],
@ -346,6 +345,7 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "is_free_item",
"fieldname": "is_free_item", "fieldname": "is_free_item",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Is Free Item", "label": "Is Free Item",
@ -508,9 +508,10 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "delivered_by_supplier",
"fieldname": "delivered_by_supplier", "fieldname": "delivered_by_supplier",
"fieldtype": "Check", "fieldtype": "Check",
"label": "To be delivered to customer", "label": "To be Delivered to Customer",
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
@ -558,6 +559,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
"fieldname": "bom", "fieldname": "bom",
"fieldtype": "Link", "fieldtype": "Link",
"label": "BOM", "label": "BOM",
@ -574,21 +576,21 @@
}, },
{ {
"fieldname": "section_break_56", "fieldname": "section_break_56",
"fieldtype": "Section Break" "fieldtype": "Section Break",
"label": "Billed, Received & Returned"
}, },
{ {
"fieldname": "stock_qty", "fieldname": "stock_qty",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Qty as per Stock UOM", "label": "Qty in Stock UOM",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "stock_qty",
"oldfieldtype": "Currency",
"print_hide": 1, "print_hide": 1,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 1,
"width": "100px" "width": "100px"
}, },
{ {
"depends_on": "received_qty",
"fieldname": "received_qty", "fieldname": "received_qty",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Received Qty", "label": "Received Qty",
@ -612,9 +614,10 @@
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"depends_on": "billed_amt",
"fieldname": "billed_amt", "fieldname": "billed_amt",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Billed Amt", "label": "Billed Amount",
"no_copy": 1, "no_copy": 1,
"options": "currency", "options": "currency",
"print_hide": 1, "print_hide": 1,
@ -633,6 +636,7 @@
"report_hide": 1 "report_hide": 1
}, },
{ {
"collapsible": 1,
"fieldname": "accounting_details", "fieldname": "accounting_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Accounting Details" "label": "Accounting Details"
@ -644,10 +648,6 @@
"options": "Account", "options": "Account",
"print_hide": 1 "print_hide": 1
}, },
{
"fieldname": "column_break_68",
"fieldtype": "Column Break"
},
{ {
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
@ -715,6 +715,7 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "is_fixed_asset",
"fetch_from": "item_code.is_fixed_asset", "fetch_from": "item_code.is_fixed_asset",
"fieldname": "is_fixed_asset", "fieldname": "is_fixed_asset",
"fieldtype": "Check", "fieldtype": "Check",
@ -728,9 +729,10 @@
} }
], ],
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-04-21 11:55:58.643393", "modified": "2020-10-30 11:59:47.670951",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order Item", "name": "Purchase Order Item",

View File

@ -23,8 +23,7 @@
{ {
"fieldname": "contract_terms", "fieldname": "contract_terms",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"label": "Contract Terms and Conditions", "label": "Contract Terms and Conditions"
"read_only": 1
}, },
{ {
"fieldname": "sb_fulfilment", "fieldname": "sb_fulfilment",
@ -45,7 +44,7 @@
} }
], ],
"links": [], "links": [],
"modified": "2020-06-03 00:24:58.179816", "modified": "2020-11-11 17:49:44.879363",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Contract Template", "name": "Contract Template",

View File

@ -2,12 +2,13 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
import json import json
from frappe.utils import cstr, cint, nowdate, flt from frappe.utils import cstr, cint, nowdate, getdate, flt, get_request_session, get_datetime
from erpnext.erpnext_integrations.utils import validate_webhooks_request from erpnext.erpnext_integrations.utils import validate_webhooks_request
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
@frappe.whitelist(allow_guest=True) @frappe.whitelist(allow_guest=True)
@validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret') @validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
@ -18,7 +19,7 @@ def store_request_data(order=None, event=None):
dump_request_data(order, event) dump_request_data(order, event)
def sync_sales_order(order, request_id=None): def sync_sales_order(order, request_id=None, old_order_sync=False):
frappe.set_user('Administrator') frappe.set_user('Administrator')
shopify_settings = frappe.get_doc("Shopify Settings") shopify_settings = frappe.get_doc("Shopify Settings")
frappe.flags.request_id = request_id frappe.flags.request_id = request_id
@ -27,7 +28,7 @@ def sync_sales_order(order, request_id=None):
try: try:
validate_customer(order, shopify_settings) validate_customer(order, shopify_settings)
validate_item(order, shopify_settings) validate_item(order, shopify_settings)
create_order(order, shopify_settings) create_order(order, shopify_settings, old_order_sync=old_order_sync)
except Exception as e: except Exception as e:
make_shopify_log(status="Error", exception=e) make_shopify_log(status="Error", exception=e)
@ -77,13 +78,13 @@ def validate_item(order, shopify_settings):
if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"): if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"):
sync_item_from_shopify(shopify_settings, item) sync_item_from_shopify(shopify_settings, item)
def create_order(order, shopify_settings, company=None): def create_order(order, shopify_settings, old_order_sync=False, company=None):
so = create_sales_order(order, shopify_settings, company) so = create_sales_order(order, shopify_settings, company)
if so: if so:
if order.get("financial_status") == "paid": if order.get("financial_status") == "paid":
create_sales_invoice(order, shopify_settings, so) create_sales_invoice(order, shopify_settings, so, old_order_sync=old_order_sync)
if order.get("fulfillments"): if order.get("fulfillments") and not old_order_sync:
create_delivery_note(order, shopify_settings, so) create_delivery_note(order, shopify_settings, so)
def create_sales_order(shopify_order, shopify_settings, company=None): def create_sales_order(shopify_order, shopify_settings, company=None):
@ -92,7 +93,7 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name") so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name")
if not so: if not so:
items = get_order_items(shopify_order.get("line_items"), shopify_settings) items = get_order_items(shopify_order.get("line_items"), shopify_settings, getdate(shopify_order.get('created_at')))
if not items: if not items:
message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master' message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master'
@ -106,8 +107,10 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
"doctype": "Sales Order", "doctype": "Sales Order",
"naming_series": shopify_settings.sales_order_series or "SO-Shopify-", "naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
"shopify_order_id": shopify_order.get("id"), "shopify_order_id": shopify_order.get("id"),
"shopify_order_number": shopify_order.get("name"),
"customer": customer or shopify_settings.default_customer, "customer": customer or shopify_settings.default_customer,
"delivery_date": nowdate(), "transaction_date": getdate(shopify_order.get("created_at")) or nowdate(),
"delivery_date": getdate(shopify_order.get("created_at")) or nowdate(),
"company": shopify_settings.company, "company": shopify_settings.company,
"selling_price_list": shopify_settings.price_list, "selling_price_list": shopify_settings.price_list,
"ignore_pricing_rule": 1, "ignore_pricing_rule": 1,
@ -132,12 +135,20 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
frappe.db.commit() frappe.db.commit()
return so return so
def create_sales_invoice(shopify_order, shopify_settings, so): def create_sales_invoice(shopify_order, shopify_settings, so, old_order_sync=False):
if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\ if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\
and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice): and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice):
if old_order_sync:
posting_date = getdate(shopify_order.get('created_at'))
else:
posting_date = nowdate()
si = make_sales_invoice(so.name, ignore_permissions=True) si = make_sales_invoice(so.name, ignore_permissions=True)
si.shopify_order_id = shopify_order.get("id") si.shopify_order_id = shopify_order.get("id")
si.shopify_order_number = shopify_order.get("name")
si.set_posting_time = 1
si.posting_date = posting_date
si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-" si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
si.flags.ignore_mandatory = True si.flags.ignore_mandatory = True
set_cost_center(si.items, shopify_settings.cost_center) set_cost_center(si.items, shopify_settings.cost_center)
@ -169,6 +180,9 @@ def create_delivery_note(shopify_order, shopify_settings, so):
dn = make_delivery_note(so.name) dn = make_delivery_note(so.name)
dn.shopify_order_id = fulfillment.get("order_id") dn.shopify_order_id = fulfillment.get("order_id")
dn.shopify_order_number = shopify_order.get("name")
dn.set_posting_time = 1
dn.posting_date = getdate(fulfillment.get("created_at"))
dn.shopify_fulfillment_id = fulfillment.get("id") dn.shopify_fulfillment_id = fulfillment.get("id")
dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-" dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-"
dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings) dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings)
@ -187,7 +201,7 @@ def get_discounted_amount(order):
discounted_amount += flt(discount.get("amount")) discounted_amount += flt(discount.get("amount"))
return discounted_amount return discounted_amount
def get_order_items(order_items, shopify_settings): def get_order_items(order_items, shopify_settings, delivery_date):
items = [] items = []
all_product_exists = True all_product_exists = True
product_not_exists = [] product_not_exists = []
@ -205,7 +219,7 @@ def get_order_items(order_items, shopify_settings):
"item_code": item_code, "item_code": item_code,
"item_name": shopify_item.get("name"), "item_name": shopify_item.get("name"),
"rate": shopify_item.get("price"), "rate": shopify_item.get("price"),
"delivery_date": nowdate(), "delivery_date": delivery_date,
"qty": shopify_item.get("quantity"), "qty": shopify_item.get("quantity"),
"stock_uom": shopify_item.get("uom") or _("Nos"), "stock_uom": shopify_item.get("uom") or _("Nos"),
"warehouse": shopify_settings.warehouse "warehouse": shopify_settings.warehouse
@ -265,3 +279,64 @@ def get_tax_account_head(tax):
frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title"))) frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title")))
return tax_account return tax_account
@frappe.whitelist(allow_guest=True)
def sync_old_orders():
frappe.set_user('Administrator')
shopify_settings = frappe.get_doc('Shopify Settings')
if not shopify_settings.sync_missing_orders:
return
url = get_url(shopify_settings)
session = get_request_session()
try:
res = session.get(url, headers=get_header(shopify_settings))
res.raise_for_status()
orders = res.json()["orders"]
for order in orders:
if is_sync_complete(shopify_settings, order):
stop_sync(shopify_settings)
return
sync_sales_order(order=order, old_order_sync=True)
last_order_id = order.get('id')
if last_order_id:
shopify_settings.load_from_db()
shopify_settings.last_order_id = last_order_id
shopify_settings.save()
frappe.db.commit()
except Exception as e:
raise e
def stop_sync(shopify_settings):
shopify_settings.sync_missing_orders = 0
shopify_settings.last_order_id = ''
shopify_settings.save()
frappe.db.commit()
def get_url(shopify_settings):
last_order_id = shopify_settings.last_order_id
if not last_order_id:
if shopify_settings.sync_based_on == 'Date':
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
get_datetime(shopify_settings.from_date)), shopify_settings)
else:
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
shopify_settings.from_order_id), shopify_settings)
else:
url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
return url
def is_sync_complete(shopify_settings, order):
if shopify_settings.sync_based_on == 'Date':
return getdate(shopify_settings.to_date) < getdate(order.get('created_at'))
else:
return cstr(order.get('id')) == cstr(shopify_settings.to_order_id)

View File

@ -1,7 +1,9 @@
{ {
"actions": [],
"creation": "2015-05-18 05:21:07.270859", "creation": "2015-05-18 05:21:07.270859",
"doctype": "DocType", "doctype": "DocType",
"document_type": "System", "document_type": "System",
"engine": "InnoDB",
"field_order": [ "field_order": [
"status_html", "status_html",
"enable_shopify", "enable_shopify",
@ -40,7 +42,16 @@
"sales_invoice_series", "sales_invoice_series",
"section_break_22", "section_break_22",
"html_16", "html_16",
"taxes" "taxes",
"syncing_details_section",
"sync_missing_orders",
"sync_based_on",
"column_break_41",
"from_date",
"to_date",
"from_order_id",
"to_order_id",
"last_order_id"
], ],
"fields": [ "fields": [
{ {
@ -255,10 +266,71 @@
"fieldtype": "Table", "fieldtype": "Table",
"label": "Shopify Tax Account", "label": "Shopify Tax Account",
"options": "Shopify Tax Account" "options": "Shopify Tax Account"
},
{
"collapsible": 1,
"fieldname": "syncing_details_section",
"fieldtype": "Section Break",
"label": "Syncing Missing Orders"
},
{
"depends_on": "eval:doc.sync_missing_orders",
"fieldname": "last_order_id",
"fieldtype": "Data",
"label": "Last Order Id",
"read_only": 1
},
{
"fieldname": "column_break_41",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "On checking this Order from the ",
"fieldname": "sync_missing_orders",
"fieldtype": "Check",
"label": "Sync Missing Old Shopify Orders"
},
{
"depends_on": "eval:doc.sync_missing_orders",
"fieldname": "sync_based_on",
"fieldtype": "Select",
"label": "Sync Based On",
"mandatory_depends_on": "eval:doc.sync_missing_orders",
"options": "\nDate\nShopify Order Id"
},
{
"depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date",
"mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
},
{
"depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date",
"mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
},
{
"depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
"fieldname": "from_order_id",
"fieldtype": "Data",
"label": "From Order Id",
"mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
},
{
"depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
"fieldname": "to_order_id",
"fieldtype": "Data",
"label": "To Order Id",
"mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
} }
], ],
"issingle": 1, "issingle": 1,
"modified": "2020-09-18 17:26:09.703215", "links": [],
"modified": "2020-11-05 20:44:03.664891",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "ERPNext Integrations", "module": "ERPNext Integrations",
"name": "Shopify Settings", "name": "Shopify Settings",

View File

@ -87,7 +87,7 @@ def get_shopify_url(path, settings):
def get_header(settings): def get_header(settings):
header = {'Content-Type': 'application/json'} header = {'Content-Type': 'application/json'}
return header; return header
@frappe.whitelist() @frappe.whitelist()
def get_series(): def get_series():
@ -121,17 +121,23 @@ def setup_custom_fields():
], ],
"Sales Order": [ "Sales Order": [
dict(fieldname='shopify_order_id', label='Shopify Order Id', dict(fieldname='shopify_order_id', label='Shopify Order Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1) fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
dict(fieldname='shopify_order_number', label='Shopify Order Number',
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
], ],
"Delivery Note":[ "Delivery Note":[
dict(fieldname='shopify_order_id', label='Shopify Order Id', dict(fieldname='shopify_order_id', label='Shopify Order Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1), fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
dict(fieldname='shopify_order_number', label='Shopify Order Number',
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1),
dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id', dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1) fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
], ],
"Sales Invoice": [ "Sales Invoice": [
dict(fieldname='shopify_order_id', label='Shopify Order Id', dict(fieldname='shopify_order_id', label='Shopify Order Id',
fieldtype='Data', insert_after='title', read_only=1, print_hide=1) fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
dict(fieldname='shopify_order_number', label='Shopify Order Number',
fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
] ]
} }

View File

@ -75,7 +75,7 @@ class ShopifySettings(unittest.TestCase):
with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_order.json")) as shopify_order: with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_order.json")) as shopify_order:
shopify_order = json.load(shopify_order) shopify_order = json.load(shopify_order)
create_order(shopify_order.get("order"), self.shopify_settings, "_Test Company") create_order(shopify_order.get("order"), self.shopify_settings, False, company="_Test Company")
sales_order = frappe.get_doc("Sales Order", {"shopify_order_id": cstr(shopify_order.get("order").get("id"))}) sales_order = frappe.get_doc("Sales Order", {"shopify_order_id": cstr(shopify_order.get("order").get("id"))})

View File

@ -307,6 +307,7 @@ scheduler_events = {
"erpnext.projects.doctype.project.project.collect_project_status", "erpnext.projects.doctype.project.project.collect_project_status",
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts", "erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance", "erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
], ],
"daily": [ "daily": [
"erpnext.stock.reorder_item.reorder_item", "erpnext.stock.reorder_item.reorder_item",

View File

@ -24,10 +24,10 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
} }
window.location.href = repl(frappe.request.url + window.location.href = repl(frappe.request.url +
'?cmd=%(cmd)s&from_date=%(from_date)s&to_date=%(to_date)s', { '?cmd=%(cmd)s&from_date=%(from_date)s&to_date=%(to_date)s', {
cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template", cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template",
from_date: this.frm.doc.att_fr_date, from_date: this.frm.doc.att_fr_date,
to_date: this.frm.doc.att_to_date, to_date: this.frm.doc.att_to_date,
}); });
}, },
show_upload() { show_upload() {

View File

@ -28,7 +28,12 @@ def get_template():
w = UnicodeWriter() w = UnicodeWriter()
w = add_header(w) w = add_header(w)
w = add_data(w, args) try:
w = add_data(w, args)
except Exception as e:
frappe.clear_messages()
frappe.respond_as_web_page("Holiday List Missing", html=e)
return
# write out response as a type csv # write out response as a type csv
frappe.response['result'] = cstr(w.getvalue()) frappe.response['result'] = cstr(w.getvalue())

View File

@ -76,6 +76,7 @@ class BOM(WebsiteGenerator):
self.set_routing_operations() self.set_routing_operations()
self.validate_operations() self.validate_operations()
self.calculate_cost() self.calculate_cost()
self.update_stock_qty()
self.update_cost(update_parent=False, from_child_bom=True, save=False) self.update_cost(update_parent=False, from_child_bom=True, save=False)
def get_context(self, context): def get_context(self, context):
@ -84,8 +85,6 @@ class BOM(WebsiteGenerator):
def on_update(self): def on_update(self):
frappe.cache().hdel('bom_children', self.name) frappe.cache().hdel('bom_children', self.name)
self.check_recursion() self.check_recursion()
self.update_stock_qty()
self.update_exploded_items()
def on_submit(self): def on_submit(self):
self.manage_default_bom() self.manage_default_bom()
@ -237,7 +236,8 @@ class BOM(WebsiteGenerator):
self.calculate_cost() self.calculate_cost()
if save: if save:
self.db_update() self.db_update()
self.update_exploded_items()
self.update_exploded_items(save=save)
# update parent BOMs # update parent BOMs
if self.total_cost != existing_bom_cost and update_parent: if self.total_cost != existing_bom_cost and update_parent:
@ -318,8 +318,6 @@ class BOM(WebsiteGenerator):
m.uom = m.stock_uom m.uom = m.stock_uom
m.qty = m.stock_qty m.qty = m.stock_qty
m.db_update()
def validate_uom_is_interger(self): def validate_uom_is_interger(self):
from erpnext.utilities.transaction_base import validate_uom_is_integer from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "uom", "qty", "BOM Item") validate_uom_is_integer(self, "uom", "qty", "BOM Item")
@ -372,15 +370,6 @@ class BOM(WebsiteGenerator):
if raise_exception: if raise_exception:
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name)) frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
def update_cost_and_exploded_items(self, bom_list=[]):
bom_list = self.traverse_tree(bom_list)
for bom in bom_list:
bom_obj = frappe.get_doc("BOM", bom)
bom_obj.check_recursion(bom_list=bom_list)
bom_obj.update_exploded_items()
return bom_list
def traverse_tree(self, bom_list=None): def traverse_tree(self, bom_list=None):
def _get_children(bom_no): def _get_children(bom_no):
children = frappe.cache().hget('bom_children', bom_no) children = frappe.cache().hget('bom_children', bom_no)
@ -472,10 +461,10 @@ class BOM(WebsiteGenerator):
d.rate = rate d.rate = rate
d.amount = (d.stock_qty or d.qty) * rate d.amount = (d.stock_qty or d.qty) * rate
def update_exploded_items(self): def update_exploded_items(self, save=True):
""" Update Flat BOM, following will be correct data""" """ Update Flat BOM, following will be correct data"""
self.get_exploded_items() self.get_exploded_items()
self.add_exploded_items() self.add_exploded_items(save=save)
def get_exploded_items(self): def get_exploded_items(self):
""" Get all raw materials including items from child bom""" """ Get all raw materials including items from child bom"""
@ -544,11 +533,13 @@ class BOM(WebsiteGenerator):
'sourced_by_supplier': d.get('sourced_by_supplier', 0) 'sourced_by_supplier': d.get('sourced_by_supplier', 0)
})) }))
def add_exploded_items(self): def add_exploded_items(self, save=True):
"Add items to Flat BOM table" "Add items to Flat BOM table"
frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
self.set('exploded_items', []) self.set('exploded_items', [])
if save:
frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
for d in sorted(self.cur_exploded_items, key=itemgetter(0)): for d in sorted(self.cur_exploded_items, key=itemgetter(0)):
ch = self.append('exploded_items', {}) ch = self.append('exploded_items', {})
for i in self.cur_exploded_items[d].keys(): for i in self.cur_exploded_items[d].keys():
@ -556,7 +547,9 @@ class BOM(WebsiteGenerator):
ch.amount = flt(ch.stock_qty) * flt(ch.rate) ch.amount = flt(ch.stock_qty) * flt(ch.rate)
ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity) ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
ch.docstatus = self.docstatus ch.docstatus = self.docstatus
ch.db_insert()
if save:
ch.db_insert()
def validate_bom_links(self): def validate_bom_links(self):
if not self.is_active: if not self.is_active:

View File

@ -443,6 +443,11 @@ class TestWorkOrder(unittest.TestCase):
ste1 = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 1)) ste1 = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 1))
self.assertEqual(len(ste1.items), 3) self.assertEqual(len(ste1.items), 3)
def test_cost_center_for_manufacture(self):
wo_order = make_wo_order_test_record()
ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
def test_operation_time_with_batch_size(self): def test_operation_time_with_batch_size(self):
fg_item = "Test Batch Size Item For BOM" fg_item = "Test Batch Size Item For BOM"
rm1 = "Test Batch Size Item RM 1 For BOM" rm1 = "Test Batch Size Item RM 1 For BOM"

View File

@ -733,4 +733,5 @@ erpnext.patches.v13_0.print_uom_after_quantity_patch
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
erpnext.patches.v13_0.update_reason_for_resignation_in_employee erpnext.patches.v13_0.update_reason_for_resignation_in_employee
erpnext.patches.v13_0.update_custom_fields_for_shopify
execute:frappe.delete_doc("Report", "Quoted Item Comparison") execute:frappe.delete_doc("Report", "Quoted Item Comparison")

View File

@ -0,0 +1,10 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import setup_custom_fields
def execute():
if frappe.db.get_single_value('Shopify Settings', 'enable_shopify'):
setup_custom_fields()

View File

@ -2,7 +2,7 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('DATEV Settings', { frappe.ui.form.on('DATEV Settings', {
// refresh: function(frm) { refresh: function(frm) {
frm.add_custom_button('Show Report', () => frappe.set_route('query-report', 'DATEV'), "fa fa-table");
// } }
}); });

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "field:client", "autoname": "field:client",
"creation": "2019-08-13 23:56:34.259906", "creation": "2019-08-13 23:56:34.259906",
"doctype": "DocType", "doctype": "DocType",
@ -6,6 +7,7 @@
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"client", "client",
"account_number_length",
"column_break_2", "column_break_2",
"client_number", "client_number",
"section_break_4", "section_break_4",
@ -28,8 +30,8 @@
"fieldtype": "Data", "fieldtype": "Data",
"in_list_view": 1, "in_list_view": 1,
"label": "Client ID", "label": "Client ID",
"reqd": 1, "length": 5,
"length": 5 "reqd": 1
}, },
{ {
"fieldname": "consultant", "fieldname": "consultant",
@ -43,8 +45,8 @@
"fieldtype": "Data", "fieldtype": "Data",
"in_list_view": 1, "in_list_view": 1,
"label": "Consultant ID", "label": "Consultant ID",
"reqd": 1, "length": 7,
"length": 7 "reqd": 1
}, },
{ {
"fieldname": "column_break_2", "fieldname": "column_break_2",
@ -57,9 +59,17 @@
{ {
"fieldname": "column_break_6", "fieldname": "column_break_6",
"fieldtype": "Column Break" "fieldtype": "Column Break"
},
{
"default": "4",
"fieldname": "account_number_length",
"fieldtype": "Int",
"label": "Account Number Length",
"reqd": 1
} }
], ],
"modified": "2019-08-14 00:03:26.616460", "links": [],
"modified": "2020-11-05 17:52:11.674329",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Regional", "module": "Regional",
"name": "DATEV Settings", "name": "DATEV Settings",

View File

@ -106,7 +106,7 @@ def get_header(filters, csv_class):
# M = Start of the fiscal year (Wirtschaftsjahresbeginn) # M = Start of the fiscal year (Wirtschaftsjahresbeginn)
frappe.utils.formatdate(filters.get('fiscal_year_start'), 'yyyyMMdd'), frappe.utils.formatdate(filters.get('fiscal_year_start'), 'yyyyMMdd'),
# N = Length of account numbers (Sachkontenlänge) # N = Length of account numbers (Sachkontenlänge)
datev_settings.get('account_number_length', '4'), str(filters.get('account_number_length', 4)),
# O = Transaction batch start date (YYYYMMDD) # O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), 'yyyyMMdd') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', frappe.utils.formatdate(filters.get('from_date'), 'yyyyMMdd') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
# P = Transaction batch end date (YYYYMMDD) # P = Transaction batch end date (YYYYMMDD)

View File

@ -11,14 +11,14 @@ frappe.query_reports["DATEV"] = {
{ {
"fieldname": "from_date", "fieldname": "from_date",
"label": __("From Date"), "label": __("From Date"),
"default": frappe.datetime.month_start(), "default": moment().subtract(1, 'month').startOf('month').format(),
"fieldtype": "Date", "fieldtype": "Date",
"reqd": 1 "reqd": 1
}, },
{ {
"fieldname": "to_date", "fieldname": "to_date",
"label": __("To Date"), "label": __("To Date"),
"default": frappe.datetime.now_date(), "default": moment().subtract(1, 'month').endOf('month').format(),
"fieldtype": "Date", "fieldtype": "Date",
"reqd": 1 "reqd": 1
}, },
@ -30,9 +30,23 @@ frappe.query_reports["DATEV"] = {
} }
], ],
onload: function(query_report) { onload: function(query_report) {
let company = frappe.query_report.get_filter_value('company');
frappe.db.exists('DATEV Settings', company).then((settings_exist) => {
if (!settings_exist) {
frappe.confirm(__('DATEV Settings for your Company are missing. Would you like to create them now?'),
() => frappe.new_doc('DATEV Settings', {'company': company})
);
}
});
query_report.page.add_menu_item(__("Download DATEV File"), () => { query_report.page.add_menu_item(__("Download DATEV File"), () => {
const filters = JSON.stringify(query_report.get_values()); const filters = JSON.stringify(query_report.get_values());
window.open(`/api/method/erpnext.regional.report.datev.datev.download_datev_csv?filters=${filters}`); window.open(`/api/method/erpnext.regional.report.datev.datev.download_datev_csv?filters=${filters}`);
}); });
query_report.page.add_menu_item(__("Change DATEV Settings"), () => {
let company = frappe.query_report.get_filter_value('company'); // read company from filters again it might have changed by now.
frappe.set_route('Form', 'DATEV Settings', company);
});
} }
}; };

View File

@ -94,8 +94,11 @@ COLUMNS = [
def execute(filters=None): def execute(filters=None):
"""Entry point for frappe.""" """Entry point for frappe."""
validate(filters) data = []
return COLUMNS, get_transactions(filters, as_dict=0) if filters and validate(filters):
data = get_transactions(filters, as_dict=0)
return COLUMNS, data
def validate(filters): def validate(filters):
@ -114,10 +117,14 @@ def validate(filters):
validate_fiscal_year(from_date, to_date, company) validate_fiscal_year(from_date, to_date, company)
try: if not frappe.db.exists('DATEV Settings', filters.get('company')):
frappe.get_doc('DATEV Settings', filters.get('company')) frappe.log_error(_('Please create {} for Company {}.').format(
except frappe.DoesNotExistError: '<a href="desk#List/DATEV%20Settings/List">{}</a>'.format(_('DATEV Settings')),
frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company'))) frappe.bold(filters.get('company'))
))
return False
return True
def validate_fiscal_year(from_date, to_date, company): def validate_fiscal_year(from_date, to_date, company):
@ -340,6 +347,8 @@ def download_datev_csv(filters):
coa = frappe.get_value('Company', company, 'chart_of_accounts') coa = frappe.get_value('Company', company, 'chart_of_accounts')
filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '') filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '')
filters['account_number_length'] = frappe.get_value('DATEV Settings', company, 'account_number_length')
transactions = get_transactions(filters) transactions = get_transactions(filters)
account_names = get_account_names(filters) account_names = get_account_names(filters)
customers = get_customers(filters) customers = get_customers(filters)

View File

@ -1227,8 +1227,6 @@ class StockEntry(StockController):
return item_dict return item_dict
def add_to_stock_entry_detail(self, item_dict, bom_no=None): def add_to_stock_entry_detail(self, item_dict, bom_no=None):
cost_center = frappe.db.get_value("Company", self.company, 'cost_center')
for d in item_dict: for d in item_dict:
stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom") stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
@ -1239,9 +1237,10 @@ class StockEntry(StockController):
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
se_child.stock_uom = stock_uom se_child.stock_uom = stock_uom
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty")) se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0) se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
se_child.subcontracted_item = item_dict[d].get("main_item_code") se_child.subcontracted_item = item_dict[d].get("main_item_code")
se_child.cost_center = (item_dict[d].get("cost_center") or
get_default_cost_center(item_dict[d], company = self.company))
for field in ["idx", "po_detail", "original_item", for field in ["idx", "po_detail", "original_item",
"expense_account", "description", "item_name"]: "expense_account", "description", "item_name"]:

View File

@ -559,23 +559,40 @@ def get_default_deferred_account(args, item, fieldname=None):
else: else:
return None return None
def get_default_cost_center(args, item, item_group, brand, company=None): def get_default_cost_center(args, item=None, item_group=None, brand=None, company=None):
cost_center = None cost_center = None
if not company and args.get("company"):
company = args.get("company")
if args.get('project'): if args.get('project'):
cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True) cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True)
if not cost_center: if not cost_center and (item and item_group and brand):
if args.get('customer'): if args.get('customer'):
cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center') or brand.get('selling_cost_center') cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center') or brand.get('selling_cost_center')
else: else:
cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center') or brand.get('buying_cost_center') cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center') or brand.get('buying_cost_center')
cost_center = cost_center or args.get("cost_center") elif not cost_center and args.get("item_code") and company:
for method in ["get_item_defaults", "get_item_group_defaults", "get_brand_defaults"]:
path = "erpnext.stock.get_item_details.{0}".format(method)
data = frappe.get_attr(path)(args.get("item_code"), company)
if data and (data.selling_cost_center or data.buying_cost_center):
return data.selling_cost_center or data.buying_cost_center
if not cost_center and args.get("cost_center"):
cost_center = args.get("cost_center")
if (company and cost_center if (company and cost_center
and frappe.get_cached_value("Cost Center", cost_center, "company") != company): and frappe.get_cached_value("Cost Center", cost_center, "company") != company):
return None return None
if not cost_center and company:
cost_center = frappe.get_cached_value("Company",
company, "cost_center")
return cost_center return cost_center
def get_default_supplier(args, item, item_group, brand): def get_default_supplier(args, item, item_group, brand):