mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-01 19:29:10 +00:00
fix:merge conflict
This commit is contained in:
@@ -6,8 +6,8 @@ import frappe, json
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
||||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||||
from frappe.core.page.dashboard.dashboard import cache_source
|
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
||||||
from frappe.utils.dateutils import get_from_date_from_timespan, get_period_ending
|
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
||||||
|
|
||||||
from frappe.utils.nestedset import get_descendants_of
|
from frappe.utils.nestedset import get_descendants_of
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,8 @@ class GLEntry(Document):
|
|||||||
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
|
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
|
||||||
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
|
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
|
||||||
|
|
||||||
if not self.flags.from_repost and self.cost_center and _check_is_group():
|
if not self.flags.from_repost and not self.voucher_type == 'Period Closing Voucher' \
|
||||||
|
and self.cost_center and _check_is_group():
|
||||||
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
|
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
|
||||||
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ def get_loyalty_details(customer, loyalty_program, expiry_date=None, company=Non
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_loyalty_program_details_with_points(customer, loyalty_program=None, expiry_date=None, company=None, silent=False, include_expired_entry=False, current_transaction_amount=0):
|
def get_loyalty_program_details_with_points(customer, loyalty_program=None, expiry_date=None, company=None, silent=False, include_expired_entry=False, current_transaction_amount=0):
|
||||||
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
|
lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent)
|
||||||
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
|
loyalty_program_name = loyalty_program or lp_details.loyalty_program
|
||||||
|
if not loyalty_program_name: return
|
||||||
|
|
||||||
|
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program_name)
|
||||||
lp_details.update(get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry))
|
lp_details.update(get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry))
|
||||||
|
|
||||||
# sort collection rule, first item on list will be lowest min_spent
|
# sort collection rule, first item on list will be lowest min_spent
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
frm.toggle_display("base_received_amount", (
|
frm.toggle_display("base_received_amount", (
|
||||||
frm.doc.paid_to_account_currency != company_currency &&
|
frm.doc.paid_to_account_currency != company_currency &&
|
||||||
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency
|
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency
|
||||||
&& frm.doc.base_paid_amount != frm.doc.base_received_amount
|
&& frm.doc.base_paid_amount != frm.doc.base_received_amount
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -386,6 +386,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
set_account_currency_and_balance: function(frm, account, currency_field,
|
set_account_currency_and_balance: function(frm, account, currency_field,
|
||||||
balance_field, callback_function) {
|
balance_field, callback_function) {
|
||||||
|
|
||||||
|
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
|
||||||
if (frm.doc.posting_date && account) {
|
if (frm.doc.posting_date && account) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
|
||||||
@@ -412,6 +414,14 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
if(!frm.doc.paid_amount && frm.doc.received_amount)
|
||||||
frm.events.received_amount(frm);
|
frm.events.received_amount(frm);
|
||||||
|
|
||||||
|
if (frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency
|
||||||
|
&& frm.doc.paid_amount != frm.doc.received_amount) {
|
||||||
|
if (company_currency != frm.doc.paid_from_account_currency &&
|
||||||
|
frm.doc.payment_type == "Pay") {
|
||||||
|
frm.doc.paid_amount = frm.doc.received_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@@ -153,8 +153,8 @@ def update_multi_mode_option(doc, pos_profile):
|
|||||||
|
|
||||||
def get_mode_of_payment(doc):
|
def get_mode_of_payment(doc):
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
select mpa.default_account, mpa.parent, mp.type as type
|
select mpa.default_account, mpa.parent, mp.type as type
|
||||||
from `tabMode of Payment Account` mpa,`tabMode of Payment` mp
|
from `tabMode of Payment Account` mpa,`tabMode of Payment` mp
|
||||||
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
|
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
|
||||||
{'company': doc.company}, as_dict=1)
|
{'company': doc.company}, as_dict=1)
|
||||||
|
|
||||||
@@ -394,6 +394,14 @@ def get_pricing_rule_data(doc):
|
|||||||
between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')
|
between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')
|
||||||
order by priority desc, name desc""",
|
order by priority desc, name desc""",
|
||||||
{'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1)
|
{'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1)
|
||||||
|
|
||||||
|
for row in pricing_rules:
|
||||||
|
if row.apply_on:
|
||||||
|
doctype = "Pricing Rule " + row.apply_on
|
||||||
|
apply_on = frappe.scrub(row.apply_on)
|
||||||
|
row[apply_on] = [d.get(apply_on) for d in frappe.get_all(doctype,
|
||||||
|
filters = {"parent": row.name}, fields = [apply_on])]
|
||||||
|
|
||||||
return pricing_rules
|
return pricing_rules
|
||||||
|
|
||||||
|
|
||||||
@@ -434,10 +442,10 @@ def make_invoice(pos_profile, doc_list={}, email_queue_list={}, customers_list={
|
|||||||
name_list.append(name)
|
name_list.append(name)
|
||||||
|
|
||||||
email_queue = make_email_queue(email_queue_list)
|
email_queue = make_email_queue(email_queue_list)
|
||||||
|
|
||||||
if isinstance(pos_profile, string_types):
|
if isinstance(pos_profile, string_types):
|
||||||
pos_profile = json.loads(pos_profile)
|
pos_profile = json.loads(pos_profile)
|
||||||
|
|
||||||
customers = get_customers_list(pos_profile)
|
customers = get_customers_list(pos_profile)
|
||||||
return {
|
return {
|
||||||
'invoice': name_list,
|
'invoice': name_list,
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ frappe.ui.form.on("Sales Invoice", {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query('transporter_address', function (doc) {
|
||||||
|
return {
|
||||||
|
query: 'frappe.contacts.doctype.address.address.address_query',
|
||||||
|
filters: {
|
||||||
|
link_doctype: 'Supplier',
|
||||||
|
link_name: doc.transporter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
frm.set_query('driver', function(doc) {
|
frm.set_query('driver', function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.utils import cint, flt, add_months, today, date_diff, getdate, add_days, cstr, nowdate
|
from frappe.utils import cint, flt, getdate, add_days, cstr, nowdate, formatdate
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
from erpnext.accounts.party import get_party_account, get_due_date
|
from erpnext.accounts.party import get_party_account, get_due_date
|
||||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||||
@@ -537,7 +537,12 @@ class SalesInvoice(SellingController):
|
|||||||
self.against_income_account = ','.join(against_acc)
|
self.against_income_account = ','.join(against_acc)
|
||||||
|
|
||||||
def add_remarks(self):
|
def add_remarks(self):
|
||||||
if not self.remarks: self.remarks = 'No Remarks'
|
if not self.remarks:
|
||||||
|
if self.po_no and self.po_date:
|
||||||
|
self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
|
||||||
|
formatdate(self.po_date))
|
||||||
|
else:
|
||||||
|
self.remarks = _("No Remarks")
|
||||||
|
|
||||||
def validate_auto_set_posting_time(self):
|
def validate_auto_set_posting_time(self):
|
||||||
# Don't auto set the posting date and time if invoice is amended
|
# Don't auto set the posting date and time if invoice is amended
|
||||||
|
|||||||
@@ -1901,8 +1901,8 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"item_code": "_Test Item",
|
"item_code": "_Test Item",
|
||||||
"uom": "Nos",
|
"uom": "Nos",
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"qty": 2000,
|
"qty": 2,
|
||||||
"rate": 12,
|
"rate": 100,
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
"expense_account": "Cost of Goods Sold - _TC",
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
@@ -1911,52 +1911,31 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"item_code": "_Test Item 2",
|
"item_code": "_Test Item 2",
|
||||||
"uom": "Nos",
|
"uom": "Nos",
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"qty": 420,
|
"qty": 4,
|
||||||
"rate": 15,
|
"rate": 150,
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
"expense_account": "Cost of Goods Sold - _TC",
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
})
|
})
|
||||||
si.discount_amount = 100
|
|
||||||
si.save()
|
si.save()
|
||||||
|
|
||||||
einvoice = make_einvoice(si)
|
einvoice = make_einvoice(si)
|
||||||
|
|
||||||
total_item_ass_value = 0
|
total_item_ass_value = sum([d['AssAmt'] for d in einvoice['ItemList']])
|
||||||
total_item_cgst_value = 0
|
total_item_cgst_value = sum([d['CgstAmt'] for d in einvoice['ItemList']])
|
||||||
total_item_sgst_value = 0
|
total_item_sgst_value = sum([d['SgstAmt'] for d in einvoice['ItemList']])
|
||||||
total_item_igst_value = 0
|
total_item_igst_value = sum([d['IgstAmt'] for d in einvoice['ItemList']])
|
||||||
total_item_value = 0
|
total_item_value = sum([d['TotItemVal'] for d in einvoice['ItemList']])
|
||||||
|
|
||||||
for item in einvoice['ItemList']:
|
|
||||||
total_item_ass_value += item['AssAmt']
|
|
||||||
total_item_cgst_value += item['CgstAmt']
|
|
||||||
total_item_sgst_value += item['SgstAmt']
|
|
||||||
total_item_igst_value += item['IgstAmt']
|
|
||||||
total_item_value += item['TotItemVal']
|
|
||||||
|
|
||||||
self.assertTrue(item['AssAmt'], item['TotAmt'] - item['Discount'])
|
|
||||||
self.assertTrue(item['TotItemVal'], item['AssAmt'] + item['CgstAmt'] + item['SgstAmt'] + item['IgstAmt'])
|
|
||||||
|
|
||||||
value_details = einvoice['ValDtls']
|
|
||||||
|
|
||||||
self.assertEqual(einvoice['Version'], '1.1')
|
self.assertEqual(einvoice['Version'], '1.1')
|
||||||
self.assertEqual(value_details['AssVal'], total_item_ass_value)
|
self.assertEqual(einvoice['ValDtls']['AssVal'], total_item_ass_value)
|
||||||
self.assertEqual(value_details['CgstVal'], total_item_cgst_value)
|
self.assertEqual(einvoice['ValDtls']['CgstVal'], total_item_cgst_value)
|
||||||
self.assertEqual(value_details['SgstVal'], total_item_sgst_value)
|
self.assertEqual(einvoice['ValDtls']['SgstVal'], total_item_sgst_value)
|
||||||
self.assertEqual(value_details['IgstVal'], total_item_igst_value)
|
self.assertEqual(einvoice['ValDtls']['IgstVal'], total_item_igst_value)
|
||||||
|
self.assertEqual(einvoice['ValDtls']['TotInvVal'], total_item_value)
|
||||||
self.assertEqual(
|
|
||||||
value_details['TotInvVal'],
|
|
||||||
value_details['AssVal'] + value_details['CgstVal']
|
|
||||||
+ value_details['SgstVal'] + value_details['IgstVal']
|
|
||||||
+ value_details['OthChrg'] - value_details['Discount']
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(value_details['TotInvVal'], si.base_grand_total)
|
|
||||||
self.assertTrue(einvoice['EwbDtls'])
|
self.assertTrue(einvoice['EwbDtls'])
|
||||||
|
|
||||||
def make_test_address_for_ewaybill():
|
def make_sales_invoice_for_ewaybill():
|
||||||
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
|
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
|
||||||
address = frappe.get_doc({
|
address = frappe.get_doc({
|
||||||
"address_line1": "_Test Address Line 1",
|
"address_line1": "_Test Address Line 1",
|
||||||
@@ -2005,7 +1984,6 @@ def make_test_address_for_ewaybill():
|
|||||||
|
|
||||||
address.save()
|
address.save()
|
||||||
|
|
||||||
def make_test_transporter_for_ewaybill():
|
|
||||||
if not frappe.db.exists('Supplier', '_Test Transporter'):
|
if not frappe.db.exists('Supplier', '_Test Transporter'):
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
"doctype": "Supplier",
|
"doctype": "Supplier",
|
||||||
@@ -2016,17 +1994,12 @@ def make_test_transporter_for_ewaybill():
|
|||||||
"is_transporter": 1
|
"is_transporter": 1
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
def make_sales_invoice_for_ewaybill():
|
|
||||||
make_test_address_for_ewaybill()
|
|
||||||
make_test_transporter_for_ewaybill()
|
|
||||||
|
|
||||||
gst_settings = frappe.get_doc("GST Settings")
|
gst_settings = frappe.get_doc("GST Settings")
|
||||||
|
|
||||||
gst_account = frappe.get_all(
|
gst_account = frappe.get_all(
|
||||||
"GST Account",
|
"GST Account",
|
||||||
fields=["cgst_account", "sgst_account", "igst_account"],
|
fields=["cgst_account", "sgst_account", "igst_account"],
|
||||||
filters = {"company": "_Test Company"}
|
filters = {"company": "_Test Company"})
|
||||||
)
|
|
||||||
|
|
||||||
if not gst_account:
|
if not gst_account:
|
||||||
gst_settings.append("gst_accounts", {
|
gst_settings.append("gst_accounts", {
|
||||||
@@ -2038,7 +2011,7 @@ def make_sales_invoice_for_ewaybill():
|
|||||||
|
|
||||||
gst_settings.save()
|
gst_settings.save()
|
||||||
|
|
||||||
si = create_sales_invoice(do_not_save=1, rate='60000')
|
si = create_sales_invoice(do_not_save =1, rate = '60000')
|
||||||
|
|
||||||
si.distance = 2000
|
si.distance = 2000
|
||||||
si.company_address = "_Test Address for Eway bill-Billing"
|
si.company_address = "_Test Address for Eway bill-Billing"
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ class Subscription(Document):
|
|||||||
if not self.generate_invoice_at_period_start:
|
if not self.generate_invoice_at_period_start:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.is_new_subscription():
|
if self.is_new_subscription() and getdate(nowdate()) >= getdate(self.current_invoice_start):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Check invoice dates and make sure it doesn't have outstanding invoices
|
# Check invoice dates and make sure it doesn't have outstanding invoices
|
||||||
|
|||||||
@@ -2018,34 +2018,57 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
apply_pricing_rule: function () {
|
apply_pricing_rule: function () {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
|
var remove_item = false;
|
||||||
$.each(this.frm.doc["items"], function (n, item) {
|
$.each(this.frm.doc["items"], function (n, item) {
|
||||||
var pricing_rule = me.get_pricing_rule(item)
|
var pricing_rule = me.get_pricing_rule(item)
|
||||||
me.validate_pricing_rule(pricing_rule)
|
me.validate_pricing_rule(pricing_rule)
|
||||||
if (pricing_rule.length) {
|
if (pricing_rule.length) {
|
||||||
item.pricing_rule = pricing_rule[0].name;
|
if (pricing_rule[0].price_or_product_discount == "Price") {
|
||||||
item.margin_type = pricing_rule[0].margin_type;
|
item.pricing_rule = pricing_rule[0].name;
|
||||||
item.price_list_rate = pricing_rule[0].price || item.price_list_rate;
|
item.margin_type = pricing_rule[0].margin_type;
|
||||||
item.margin_rate_or_amount = pricing_rule[0].margin_rate_or_amount;
|
item.price_list_rate = pricing_rule[0].price || item.price_list_rate;
|
||||||
item.discount_percentage = pricing_rule[0].discount_percentage || 0.0;
|
item.margin_rate_or_amount = pricing_rule[0].margin_rate_or_amount;
|
||||||
me.apply_pricing_rule_on_item(item)
|
item.discount_percentage = pricing_rule[0].discount_percentage || 0.0;
|
||||||
|
me.apply_pricing_rule_on_item(item)
|
||||||
|
} else {
|
||||||
|
me.child = frappe.model.add_child(me.frm.doc, me.frm.doc.doctype + " Item", "items");
|
||||||
|
me.child.item_code = pricing_rule[0].same_item ? item.item_code : pricing_rule[0].free_item;
|
||||||
|
me.child.item_name = pricing_rule[0].same_item ? item.item_name : pricing_rule[0].free_item;
|
||||||
|
me.child.stock_uom = pricing_rule[0].same_item ? item.stock_uom : pricing_rule[0].free_item_uom;
|
||||||
|
me.child.uom = pricing_rule[0].same_item ? item.uom : pricing_rule[0].free_item_uom;
|
||||||
|
me.child.conversion_factor = 1;
|
||||||
|
me.child.qty = pricing_rule.qty || 1;
|
||||||
|
me.child.is_free_item = 1;
|
||||||
|
me.child.brand = pricing_rule[0].same_item ? item.brand : "";
|
||||||
|
me.child.description = pricing_rule[0].same_item ? item.description : pricing_rule[0].free_item;
|
||||||
|
}
|
||||||
} else if (item.pricing_rule) {
|
} else if (item.pricing_rule) {
|
||||||
item.price_list_rate = me.price_list_data[item.item_code]
|
item.price_list_rate = me.price_list_data[item.item_code]
|
||||||
item.margin_rate_or_amount = 0.0;
|
item.margin_rate_or_amount = 0.0;
|
||||||
item.discount_percentage = 0.0;
|
item.discount_percentage = 0.0;
|
||||||
item.pricing_rule = null;
|
item.pricing_rule = null;
|
||||||
me.apply_pricing_rule_on_item(item)
|
me.apply_pricing_rule_on_item(item)
|
||||||
|
} else if (item.is_free_item) {
|
||||||
|
remove_item = true;
|
||||||
|
item.qty = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.discount_percentage > 0) {
|
if(item.discount_percentage > 0) {
|
||||||
me.apply_pricing_rule_on_item(item)
|
me.apply_pricing_rule_on_item(item)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
if (remove_item) {
|
||||||
|
this.remove_zero_qty_items_from_cart();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_pricing_rule: function (item) {
|
get_pricing_rule: function (item) {
|
||||||
var me = this;
|
var me = this;
|
||||||
return $.grep(this.pricing_rules, function (data) {
|
return $.grep(this.pricing_rules, function (data) {
|
||||||
if (item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty))) {
|
me.get_mixed_min_max_qty_and_amt(data, item);
|
||||||
|
if (data.mixed_qty >= data.min_qty && (data.mixed_qty <= (data.max_qty ? data.max_qty : data.mixed_qty))) {
|
||||||
if (me.validate_item_condition(data, item)) {
|
if (me.validate_item_condition(data, item)) {
|
||||||
if (in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)) {
|
if (in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)) {
|
||||||
return me.validate_condition(data)
|
return me.validate_condition(data)
|
||||||
@@ -2057,11 +2080,26 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get_mixed_min_max_qty_and_amt: function(data, item) {
|
||||||
|
var apply_on = frappe.model.scrub(data.apply_on);
|
||||||
|
data.mixed_qty = 0.0
|
||||||
|
if (data.mixed_conditions && in_list(data[apply_on], item[apply_on])) {
|
||||||
|
this.frm.doc.items.forEach(d => {
|
||||||
|
if (in_list(data[apply_on], d[apply_on])) {
|
||||||
|
data.mixed_qty += d.qty;
|
||||||
|
data.mixed_amt += d.amount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
data.mixed_qty = item.qty;
|
||||||
|
data.mixed_amt = item.amount;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
validate_item_condition: function (data, item) {
|
validate_item_condition: function (data, item) {
|
||||||
var apply_on = frappe.model.scrub(data.apply_on);
|
var apply_on = frappe.model.scrub(data.apply_on);
|
||||||
|
|
||||||
return (data.apply_on == 'Item Group')
|
return in_list(data[apply_on], item[apply_on]);
|
||||||
? this.validate_item_group(data.item_group, item.item_group) : (data[apply_on] == item[apply_on]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_item_group: function (pr_item_group, cart_item_group) {
|
validate_item_group: function (pr_item_group, cart_item_group) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from frappe.utils import flt
|
|||||||
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
|
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
|
||||||
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
|
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
|
||||||
get_group_by_conditions)
|
get_group_by_conditions)
|
||||||
|
from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return _execute(filters)
|
return _execute(filters)
|
||||||
@@ -23,7 +24,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
aii_account_map = get_aii_accounts()
|
aii_account_map = get_aii_accounts()
|
||||||
if item_list:
|
if item_list:
|
||||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
|
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
|
||||||
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
|
doctype='Purchase Invoice', tax_doctype='Purchase Taxes and Charges')
|
||||||
|
|
||||||
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
|
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
|
||||||
|
|
||||||
@@ -35,10 +36,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
if filters.get('group_by'):
|
if filters.get('group_by'):
|
||||||
grand_total = get_grand_total(filters, 'Purchase Invoice')
|
grand_total = get_grand_total(filters, 'Purchase Invoice')
|
||||||
|
|
||||||
|
item_details = get_item_details()
|
||||||
|
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
if not d.stock_qty:
|
if not d.stock_qty:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
item_record = item_details.get(d.item_code)
|
||||||
|
|
||||||
purchase_receipt = None
|
purchase_receipt = None
|
||||||
if d.purchase_receipt:
|
if d.purchase_receipt:
|
||||||
purchase_receipt = d.purchase_receipt
|
purchase_receipt = d.purchase_receipt
|
||||||
@@ -49,8 +54,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
|
|
||||||
row = {
|
row = {
|
||||||
'item_code': d.item_code,
|
'item_code': d.item_code,
|
||||||
'item_name': d.item_name,
|
'item_name': item_record.item_name,
|
||||||
'item_group': d.item_group,
|
'item_group': item_record.item_group,
|
||||||
'description': d.description,
|
'description': d.description,
|
||||||
'invoice': d.parent,
|
'invoice': d.parent,
|
||||||
'posting_date': d.posting_date,
|
'posting_date': d.posting_date,
|
||||||
@@ -82,10 +87,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||||
row.update({
|
row.update({
|
||||||
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
|
||||||
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
|
||||||
})
|
})
|
||||||
total_tax += flt(item_tax.get("tax_amount"))
|
total_tax += flt(item_tax.get('tax_amount'))
|
||||||
|
|
||||||
row.update({
|
row.update({
|
||||||
'total_tax': total_tax,
|
'total_tax': total_tax,
|
||||||
@@ -317,8 +322,8 @@ def get_items(filters, additional_query_columns):
|
|||||||
select
|
select
|
||||||
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
|
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
|
||||||
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
|
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
|
||||||
`tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, `tabPurchase Invoice Item`.`item_code`,
|
`tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total,
|
||||||
`tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`, `tabPurchase Invoice Item`.description,
|
`tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description,
|
||||||
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
|
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
|
||||||
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
|
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
|
||||||
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
|
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from frappe.utils import flt, cstr
|
|||||||
from frappe.model.meta import get_field_precision
|
from frappe.model.meta import get_field_precision
|
||||||
from frappe.utils.xlsxutils import handle_html
|
from frappe.utils.xlsxutils import handle_html
|
||||||
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
|
||||||
|
from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details, get_customer_details
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
return _execute(filters)
|
return _execute(filters)
|
||||||
@@ -17,7 +18,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
|
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
|
||||||
columns = get_columns(additional_table_columns, filters)
|
columns = get_columns(additional_table_columns, filters)
|
||||||
|
|
||||||
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
|
company_currency = frappe.get_cached_value('Company', filters.get('company'), 'default_currency')
|
||||||
|
|
||||||
item_list = get_items(filters, additional_query_columns)
|
item_list = get_items(filters, additional_query_columns)
|
||||||
if item_list:
|
if item_list:
|
||||||
@@ -34,7 +35,13 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
if filters.get('group_by'):
|
if filters.get('group_by'):
|
||||||
grand_total = get_grand_total(filters, 'Sales Invoice')
|
grand_total = get_grand_total(filters, 'Sales Invoice')
|
||||||
|
|
||||||
|
customer_details = get_customer_details()
|
||||||
|
item_details = get_item_details()
|
||||||
|
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
|
customer_record = customer_details.get(d.customer)
|
||||||
|
item_record = item_details.get(d.item_code)
|
||||||
|
|
||||||
delivery_note = None
|
delivery_note = None
|
||||||
if d.delivery_note:
|
if d.delivery_note:
|
||||||
delivery_note = d.delivery_note
|
delivery_note = d.delivery_note
|
||||||
@@ -46,14 +53,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
|
|
||||||
row = {
|
row = {
|
||||||
'item_code': d.item_code,
|
'item_code': d.item_code,
|
||||||
'item_name': d.item_name,
|
'item_name': item_record.item_name,
|
||||||
'item_group': d.item_group,
|
'item_group': item_record.item_group,
|
||||||
'description': d.description,
|
'description': d.description,
|
||||||
'invoice': d.parent,
|
'invoice': d.parent,
|
||||||
'posting_date': d.posting_date,
|
'posting_date': d.posting_date,
|
||||||
'customer': d.customer,
|
'customer': d.customer,
|
||||||
'customer_name': d.customer_name,
|
'customer_name': customer_record.customer_name,
|
||||||
'customer_group': d.customer_group,
|
'customer_group': customer_record.customer_group,
|
||||||
}
|
}
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
@@ -91,10 +98,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
for tax in tax_columns:
|
for tax in tax_columns:
|
||||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||||
row.update({
|
row.update({
|
||||||
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
|
frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
|
||||||
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
|
frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
|
||||||
})
|
})
|
||||||
total_tax += flt(item_tax.get("tax_amount"))
|
total_tax += flt(item_tax.get('tax_amount'))
|
||||||
|
|
||||||
row.update({
|
row.update({
|
||||||
'total_tax': total_tax,
|
'total_tax': total_tax,
|
||||||
@@ -227,7 +234,7 @@ def get_columns(additional_table_columns, filters):
|
|||||||
if filters.get('group_by') != 'Terriotory':
|
if filters.get('group_by') != 'Terriotory':
|
||||||
columns.extend([
|
columns.extend([
|
||||||
{
|
{
|
||||||
'label': _("Territory"),
|
'label': _('Territory'),
|
||||||
'fieldname': 'territory',
|
'fieldname': 'territory',
|
||||||
'fieldtype': 'Link',
|
'fieldtype': 'Link',
|
||||||
'options': 'Territory',
|
'options': 'Territory',
|
||||||
@@ -382,13 +389,12 @@ def get_items(filters, additional_query_columns):
|
|||||||
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
|
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
|
||||||
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
|
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
|
||||||
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
|
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
|
||||||
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.item_name,
|
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
|
||||||
`tabSales Invoice Item`.item_group, `tabSales Invoice Item`.description, `tabSales Invoice Item`.sales_order,
|
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
|
||||||
`tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account,
|
`tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
|
||||||
`tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty,
|
`tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
|
||||||
`tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
|
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
|
||||||
`tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
|
`tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
|
||||||
`tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
|
|
||||||
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
|
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
|
||||||
from `tabSales Invoice`, `tabSales Invoice Item`
|
from `tabSales Invoice`, `tabSales Invoice Item`
|
||||||
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
|
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
|
||||||
@@ -425,14 +431,14 @@ def get_deducted_taxes():
|
|||||||
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
|
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
|
||||||
|
|
||||||
def get_tax_accounts(item_list, columns, company_currency,
|
def get_tax_accounts(item_list, columns, company_currency,
|
||||||
doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
|
doctype='Sales Invoice', tax_doctype='Sales Taxes and Charges'):
|
||||||
import json
|
import json
|
||||||
item_row_map = {}
|
item_row_map = {}
|
||||||
tax_columns = []
|
tax_columns = []
|
||||||
invoice_item_row = {}
|
invoice_item_row = {}
|
||||||
itemised_tax = {}
|
itemised_tax = {}
|
||||||
|
|
||||||
tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"),
|
tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field('tax_amount'),
|
||||||
currency=company_currency) or 2
|
currency=company_currency) or 2
|
||||||
|
|
||||||
for d in item_list:
|
for d in item_list:
|
||||||
@@ -477,8 +483,8 @@ def get_tax_accounts(item_list, columns, company_currency,
|
|||||||
tax_rate = tax_data
|
tax_rate = tax_data
|
||||||
tax_amount = 0
|
tax_amount = 0
|
||||||
|
|
||||||
if charge_type == "Actual" and not tax_rate:
|
if charge_type == 'Actual' and not tax_rate:
|
||||||
tax_rate = "NA"
|
tax_rate = 'NA'
|
||||||
|
|
||||||
item_net_amount = sum([flt(d.base_net_amount)
|
item_net_amount = sum([flt(d.base_net_amount)
|
||||||
for d in item_row_map.get(parent, {}).get(item_code, [])])
|
for d in item_row_map.get(parent, {}).get(item_code, [])])
|
||||||
@@ -492,17 +498,17 @@ def get_tax_accounts(item_list, columns, company_currency,
|
|||||||
if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value)
|
if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value)
|
||||||
|
|
||||||
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
||||||
"tax_rate": tax_rate,
|
'tax_rate': tax_rate,
|
||||||
"tax_amount": tax_value
|
'tax_amount': tax_value
|
||||||
})
|
})
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
elif charge_type == "Actual" and tax_amount:
|
elif charge_type == 'Actual' and tax_amount:
|
||||||
for d in invoice_item_row.get(parent, []):
|
for d in invoice_item_row.get(parent, []):
|
||||||
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
||||||
"tax_rate": "NA",
|
'tax_rate': 'NA',
|
||||||
"tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total,
|
'tax_amount': flt((tax_amount * d.base_net_amount) / d.base_net_total,
|
||||||
tax_amount_precision)
|
tax_amount_precision)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -564,7 +570,7 @@ def add_total_row(data, filters, prev_group_by_value, item, total_row_map,
|
|||||||
})
|
})
|
||||||
|
|
||||||
total_row_map.setdefault('total_row', {
|
total_row_map.setdefault('total_row', {
|
||||||
subtotal_display_field: "Total",
|
subtotal_display_field: 'Total',
|
||||||
'stock_qty': 0.0,
|
'stock_qty': 0.0,
|
||||||
'amount': 0.0,
|
'amount': 0.0,
|
||||||
'bold': 1,
|
'bold': 1,
|
||||||
|
|||||||
@@ -59,23 +59,111 @@ def validate_filters(filters):
|
|||||||
|
|
||||||
def get_columns(filters):
|
def get_columns(filters):
|
||||||
return [
|
return [
|
||||||
_("Payment Document") + ":: 100",
|
{
|
||||||
_("Payment Entry") + ":Dynamic Link/"+_("Payment Document")+":140",
|
"fieldname": "payment_document",
|
||||||
_("Party Type") + "::100",
|
"label": _("Payment Document Type"),
|
||||||
_("Party") + ":Dynamic Link/Party Type:140",
|
"fieldtype": "Data",
|
||||||
_("Posting Date") + ":Date:100",
|
"width": 100
|
||||||
_("Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == _("Outgoing") else ":Link/Sales Invoice:130"),
|
},
|
||||||
_("Invoice Posting Date") + ":Date:130",
|
{
|
||||||
_("Payment Due Date") + ":Date:130",
|
"fieldname": "payment_entry",
|
||||||
_("Debit") + ":Currency:120",
|
"label": _("Payment Document"),
|
||||||
_("Credit") + ":Currency:120",
|
"fieldtype": "Dynamic Link",
|
||||||
_("Remarks") + "::150",
|
"options": "payment_document",
|
||||||
_("Age") +":Int:40",
|
"width": 160
|
||||||
"0-30:Currency:100",
|
},
|
||||||
"30-60:Currency:100",
|
{
|
||||||
"60-90:Currency:100",
|
"fieldname": "party_type",
|
||||||
_("90-Above") + ":Currency:100",
|
"label": _("Party Type"),
|
||||||
_("Delay in payment (Days)") + "::150"
|
"fieldtype": "Data",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "party",
|
||||||
|
"label": _("Party"),
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"options": "party_type",
|
||||||
|
"width": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "posting_date",
|
||||||
|
"label": _("Posting Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "invoice",
|
||||||
|
"label": _("Invoice"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Purchase Invoice" if filters.get("payment_type") == _("Outgoing") else "Sales Invoice",
|
||||||
|
"width": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "invoice_posting_date",
|
||||||
|
"label": _("Invoice Posting Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "due_date",
|
||||||
|
"label": _("Payment Due Date"),
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "debit",
|
||||||
|
"label": _("Debit"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "credit",
|
||||||
|
"label": _("Credit"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "remarks",
|
||||||
|
"label": _("Remarks"),
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "age",
|
||||||
|
"label": _("Age"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"width": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "range1",
|
||||||
|
"label": _("0-30"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "range2",
|
||||||
|
"label": _("30-60"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "range3",
|
||||||
|
"label": _("60-90"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "range4",
|
||||||
|
"label": _("90 Above"),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "delay_in_payment",
|
||||||
|
"label": _("Delay in payment (Days)"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"width": 100
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_conditions(filters):
|
def get_conditions(filters):
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ frappe.ui.form.on('Asset', {
|
|||||||
|
|
||||||
if (frm.doc.docstatus == 0) {
|
if (frm.doc.docstatus == 0) {
|
||||||
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
||||||
|
frm.set_df_property('depreciation_start_date', 'reqd', 1, frm.doc.name, 'finance_books');
|
||||||
|
frm.refresh_field('finance_books');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,5 @@ frappe.ui.form.on('Asset Category', {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
|
||||||
"creation": "2018-05-08 14:44:37.095570",
|
"creation": "2018-05-08 14:44:37.095570",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@@ -54,9 +53,7 @@
|
|||||||
"fieldname": "depreciation_start_date",
|
"fieldname": "depreciation_start_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Depreciation Posting Date",
|
"label": "Depreciation Posting Date"
|
||||||
"mandatory_depends_on": "eval:parent.doctype == 'Asset'",
|
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@@ -84,10 +81,8 @@
|
|||||||
"label": "Rate of Depreciation"
|
"label": "Rate of Depreciation"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"modified": "2020-12-30 15:43:03.188256",
|
||||||
"modified": "2020-10-30 15:22:29.119868",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Finance Book",
|
"name": "Asset Finance Book",
|
||||||
|
|||||||
@@ -35,9 +35,7 @@ def update_last_purchase_rate(doc, is_submit):
|
|||||||
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
||||||
|
|
||||||
# update last purchsae rate
|
# update last purchsae rate
|
||||||
if last_purchase_rate:
|
frappe.db.set_value('Item', d.item_code, 'last_purchase_rate', flt(last_purchase_rate))
|
||||||
frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
|
||||||
(flt(last_purchase_rate), d.item_code))
|
|
||||||
|
|
||||||
def validate_for_items(doc):
|
def validate_for_items(doc):
|
||||||
items = []
|
items = []
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ class BuyingController(StockController):
|
|||||||
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
|
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
|
||||||
|
|
||||||
consumed_qty = raw_material_data.get('qty', 0)
|
consumed_qty = raw_material_data.get('qty', 0)
|
||||||
consumed_serial_nos = raw_material_data.get('serial_nos', '')
|
consumed_serial_nos = raw_material_data.get('serial_no', '')
|
||||||
consumed_batch_nos = raw_material_data.get('batch_nos', '')
|
consumed_batch_nos = raw_material_data.get('batch_nos', '')
|
||||||
|
|
||||||
transferred_qty = raw_material.qty
|
transferred_qty = raw_material.qty
|
||||||
|
|||||||
@@ -245,7 +245,8 @@ doc_events = {
|
|||||||
"Sales Invoice": {
|
"Sales Invoice": {
|
||||||
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
|
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
|
||||||
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
|
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
|
||||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
"on_trash": "erpnext.regional.check_deletion_permission",
|
||||||
|
"validate": "erpnext.regional.india.utils.set_transporter_address"
|
||||||
},
|
},
|
||||||
"Purchase Invoice": {
|
"Purchase Invoice": {
|
||||||
"validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"
|
"validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"
|
||||||
|
|||||||
@@ -782,7 +782,7 @@
|
|||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 24,
|
"idx": 24,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"modified": "2020-01-09 04:23:55.611366",
|
"modified": "2020-01-09 05:23:55.611366",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
@@ -824,7 +824,6 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
|
||||||
"search_fields": "employee_name",
|
"search_fields": "employee_name",
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import date_diff, getdate, formatdate, cint, month_diff, flt
|
from frappe.utils import date_diff, getdate, formatdate, cint, month_diff, flt, add_months
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.hr.utils import get_holidays_for_employee
|
from erpnext.hr.utils import get_holidays_for_employee
|
||||||
|
|
||||||
@@ -88,6 +88,8 @@ def get_period_factor(employee, start_date, end_date, payroll_frequency, payroll
|
|||||||
period_start = joining_date
|
period_start = joining_date
|
||||||
if relieving_date and getdate(relieving_date) < getdate(period_end):
|
if relieving_date and getdate(relieving_date) < getdate(period_end):
|
||||||
period_end = relieving_date
|
period_end = relieving_date
|
||||||
|
if month_diff(period_end, start_date) > 1:
|
||||||
|
start_date = add_months(start_date, - (month_diff(period_end, start_date)+1))
|
||||||
|
|
||||||
total_sub_periods, remaining_sub_periods = 0.0, 0.0
|
total_sub_periods, remaining_sub_periods = 0.0, 0.0
|
||||||
|
|
||||||
|
|||||||
@@ -299,14 +299,17 @@ class SalarySlip(TransactionBase):
|
|||||||
def calculate_net_pay(self):
|
def calculate_net_pay(self):
|
||||||
if self.salary_structure:
|
if self.salary_structure:
|
||||||
self.calculate_component_amounts("earnings")
|
self.calculate_component_amounts("earnings")
|
||||||
self.gross_pay = self.get_component_totals("earnings")
|
self.gross_pay = self.get_component_totals("earnings", depends_on_payment_days=1)
|
||||||
|
|
||||||
if self.salary_structure:
|
if self.salary_structure:
|
||||||
self.calculate_component_amounts("deductions")
|
self.calculate_component_amounts("deductions")
|
||||||
self.total_deduction = self.get_component_totals("deductions")
|
|
||||||
|
|
||||||
self.set_loan_repayment()
|
self.set_loan_repayment()
|
||||||
|
self.set_component_amounts_based_on_payment_days()
|
||||||
|
self.set_net_pay()
|
||||||
|
|
||||||
|
def set_net_pay(self):
|
||||||
|
self.total_deduction = self.get_component_totals("deductions")
|
||||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||||
self.rounded_total = rounded(self.net_pay)
|
self.rounded_total = rounded(self.net_pay)
|
||||||
|
|
||||||
@@ -323,8 +326,6 @@ class SalarySlip(TransactionBase):
|
|||||||
else:
|
else:
|
||||||
self.add_tax_components(payroll_period)
|
self.add_tax_components(payroll_period)
|
||||||
|
|
||||||
self.set_component_amounts_based_on_payment_days(component_type)
|
|
||||||
|
|
||||||
def add_structure_components(self, component_type):
|
def add_structure_components(self, component_type):
|
||||||
data = self.get_data_for_eval()
|
data = self.get_data_for_eval()
|
||||||
for struct_row in self._salary_structure_doc.get(component_type):
|
for struct_row in self._salary_structure_doc.get(component_type):
|
||||||
@@ -679,7 +680,7 @@ class SalarySlip(TransactionBase):
|
|||||||
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
|
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
|
||||||
(not self.salary_slip_based_on_timesheet or
|
(not self.salary_slip_based_on_timesheet or
|
||||||
getdate(self.start_date) < joining_date or
|
getdate(self.start_date) < joining_date or
|
||||||
getdate(self.end_date) > relieving_date
|
(relieving_date and getdate(self.end_date) > relieving_date)
|
||||||
)):
|
)):
|
||||||
additional_amount = flt((flt(row.additional_amount) * flt(self.payment_days)
|
additional_amount = flt((flt(row.additional_amount) * flt(self.payment_days)
|
||||||
/ cint(self.total_working_days)), row.precision("additional_amount"))
|
/ cint(self.total_working_days)), row.precision("additional_amount"))
|
||||||
@@ -812,15 +813,21 @@ class SalarySlip(TransactionBase):
|
|||||||
struct_row['variable_based_on_taxable_salary'] = component.variable_based_on_taxable_salary
|
struct_row['variable_based_on_taxable_salary'] = component.variable_based_on_taxable_salary
|
||||||
return struct_row
|
return struct_row
|
||||||
|
|
||||||
def get_component_totals(self, component_type):
|
def get_component_totals(self, component_type, depends_on_payment_days=0):
|
||||||
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
total = 0.0
|
total = 0.0
|
||||||
for d in self.get(component_type):
|
for d in self.get(component_type):
|
||||||
if not d.do_not_include_in_total:
|
if not d.do_not_include_in_total:
|
||||||
d.amount = flt(d.amount, d.precision("amount"))
|
if depends_on_payment_days:
|
||||||
total += d.amount
|
amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
|
||||||
|
else:
|
||||||
|
amount = flt(d.amount, d.precision("amount"))
|
||||||
|
total += amount
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def set_component_amounts_based_on_payment_days(self, component_type):
|
def set_component_amounts_based_on_payment_days(self):
|
||||||
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
@@ -830,8 +837,9 @@ class SalarySlip(TransactionBase):
|
|||||||
if not joining_date:
|
if not joining_date:
|
||||||
frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
|
frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
|
||||||
|
|
||||||
for d in self.get(component_type):
|
for component_type in ("earnings", "deductions"):
|
||||||
d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0]
|
for d in self.get(component_type):
|
||||||
|
d.amount = flt(self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0], d.precision("amount"))
|
||||||
|
|
||||||
def set_loan_repayment(self):
|
def set_loan_repayment(self):
|
||||||
self.set('loans', [])
|
self.set('loans', [])
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ cur_frm.cscript.hour_rate = function(doc) {
|
|||||||
|
|
||||||
cur_frm.cscript.time_in_mins = cur_frm.cscript.hour_rate;
|
cur_frm.cscript.time_in_mins = cur_frm.cscript.hour_rate;
|
||||||
|
|
||||||
cur_frm.cscript.bom_no = function(doc, cdt, cdn) {
|
cur_frm.cscript.bom_no = function(doc, cdt, cdn) {
|
||||||
get_bom_material_detail(doc, cdt, cdn, false);
|
get_bom_material_detail(doc, cdt, cdn, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,17 +261,22 @@ cur_frm.cscript.is_default = function(doc) {
|
|||||||
if (doc.is_default) cur_frm.set_value("is_active", 1);
|
if (doc.is_default) cur_frm.set_value("is_active", 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
var get_bom_material_detail= function(doc, cdt, cdn, scrap_items) {
|
var get_bom_material_detail = function(doc, cdt, cdn, scrap_items) {
|
||||||
|
if (!doc.company) {
|
||||||
|
frappe.throw({message: __("Please select a Company first."), title: __("Mandatory")});
|
||||||
|
}
|
||||||
|
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
if (d.item_code) {
|
if (d.item_code) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
doc: doc,
|
doc: doc,
|
||||||
method: "get_bom_material_detail",
|
method: "get_bom_material_detail",
|
||||||
args: {
|
args: {
|
||||||
'item_code': d.item_code,
|
"company": doc.company,
|
||||||
'bom_no': d.bom_no != null ? d.bom_no: '',
|
"item_code": d.item_code,
|
||||||
|
"bom_no": d.bom_no != null ? d.bom_no: '',
|
||||||
"scrap_items": scrap_items,
|
"scrap_items": scrap_items,
|
||||||
'qty': d.qty,
|
"qty": d.qty,
|
||||||
"stock_qty": d.stock_qty,
|
"stock_qty": d.stock_qty,
|
||||||
"include_item_in_manufacturing": d.include_item_in_manufacturing,
|
"include_item_in_manufacturing": d.include_item_in_manufacturing,
|
||||||
"uom": d.uom,
|
"uom": d.uom,
|
||||||
@@ -309,7 +314,7 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (d.bom_no) {
|
if (d.bom_no) {
|
||||||
frappe.msgprint(__("You can not change rate if BOM mentioned agianst any item"));
|
frappe.msgprint(__("You cannot change the rate if BOM is mentioned against any Item."));
|
||||||
get_bom_material_detail(doc, cdt, cdn, scrap_items);
|
get_bom_material_detail(doc, cdt, cdn, scrap_items);
|
||||||
} else {
|
} else {
|
||||||
erpnext.bom.calculate_rm_cost(doc);
|
erpnext.bom.calculate_rm_cost(doc);
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.route = frappe.scrub(self.name).replace('_', '-')
|
self.route = frappe.scrub(self.name).replace('_', '-')
|
||||||
|
|
||||||
|
if not self.company:
|
||||||
|
frappe.throw(_("Please select a Company first."), title=_("Mandatory"))
|
||||||
|
|
||||||
self.clear_operations()
|
self.clear_operations()
|
||||||
self.validate_main_item()
|
self.validate_main_item()
|
||||||
self.validate_currency()
|
self.validate_currency()
|
||||||
@@ -122,6 +126,7 @@ class BOM(WebsiteGenerator):
|
|||||||
self.validate_bom_currecny(item)
|
self.validate_bom_currecny(item)
|
||||||
|
|
||||||
ret = self.get_bom_material_detail({
|
ret = self.get_bom_material_detail({
|
||||||
|
"company": self.company,
|
||||||
"item_code": item.item_code,
|
"item_code": item.item_code,
|
||||||
"item_name": item.item_name,
|
"item_name": item.item_name,
|
||||||
"bom_no": item.bom_no,
|
"bom_no": item.bom_no,
|
||||||
@@ -236,6 +241,7 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
rate = self.get_rm_rate({
|
rate = self.get_rm_rate({
|
||||||
|
"company": self.company,
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
"bom_no": d.bom_no,
|
"bom_no": d.bom_no,
|
||||||
"qty": d.qty,
|
"qty": d.qty,
|
||||||
@@ -288,10 +294,20 @@ class BOM(WebsiteGenerator):
|
|||||||
""" Get weighted average of valuation rate from all warehouses """
|
""" Get weighted average of valuation rate from all warehouses """
|
||||||
|
|
||||||
total_qty, total_value, valuation_rate = 0.0, 0.0, 0.0
|
total_qty, total_value, valuation_rate = 0.0, 0.0, 0.0
|
||||||
for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin`
|
item_bins = frappe.db.sql("""
|
||||||
where item_code=%s""", args['item_code'], as_dict=1):
|
select
|
||||||
total_qty += flt(d.actual_qty)
|
bin.actual_qty, bin.stock_value
|
||||||
total_value += flt(d.stock_value)
|
from
|
||||||
|
`tabBin` bin, `tabWarehouse` warehouse
|
||||||
|
where
|
||||||
|
bin.item_code=%(item)s
|
||||||
|
and bin.warehouse = warehouse.name
|
||||||
|
and warehouse.company=%(company)s""",
|
||||||
|
{"item": args['item_code'], "company": args['company']}, as_dict=1)
|
||||||
|
|
||||||
|
for d in item_bins:
|
||||||
|
total_qty += flt(d.actual_qty)
|
||||||
|
total_value += flt(d.stock_value)
|
||||||
|
|
||||||
if total_qty:
|
if total_qty:
|
||||||
valuation_rate = total_value / total_qty
|
valuation_rate = total_value / total_qty
|
||||||
|
|||||||
@@ -526,7 +526,6 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
ste1.submit()
|
ste1.submit()
|
||||||
ste_cancel_list.append(ste1)
|
ste_cancel_list.append(ste1)
|
||||||
|
|
||||||
print(wo_order.name)
|
|
||||||
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
||||||
self.assertEquals(ste3.fg_completed_qty, 2)
|
self.assertEquals(ste3.fg_completed_qty, 2)
|
||||||
|
|
||||||
@@ -539,6 +538,48 @@ class TestWorkOrder(unittest.TestCase):
|
|||||||
|
|
||||||
frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
|
frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
|
||||||
|
|
||||||
|
def test_extra_material_transfer(self):
|
||||||
|
frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
|
||||||
|
frappe.db.set_value("Manufacturing Settings", None, "backflush_raw_materials_based_on",
|
||||||
|
"Material Transferred for Manufacture")
|
||||||
|
|
||||||
|
wo_order = make_wo_order_test_record(planned_start_date=now(), qty=4)
|
||||||
|
|
||||||
|
ste_cancel_list = []
|
||||||
|
ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
|
||||||
|
target="_Test Warehouse - _TC", qty=20, basic_rate=5000.0)
|
||||||
|
ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
|
||||||
|
target="_Test Warehouse - _TC", qty=20, basic_rate=1000.0)
|
||||||
|
|
||||||
|
ste_cancel_list.extend([ste1, ste2])
|
||||||
|
|
||||||
|
itemwise_qty = {}
|
||||||
|
s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 4))
|
||||||
|
for row in s.items:
|
||||||
|
row.qty = row.qty + 2
|
||||||
|
itemwise_qty.setdefault(row.item_code, row.qty)
|
||||||
|
|
||||||
|
s.submit()
|
||||||
|
ste_cancel_list.append(s)
|
||||||
|
|
||||||
|
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
||||||
|
for ste_row in ste3.items:
|
||||||
|
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
||||||
|
self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
||||||
|
|
||||||
|
ste3.submit()
|
||||||
|
ste_cancel_list.append(ste3)
|
||||||
|
|
||||||
|
ste2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
||||||
|
for ste_row in ste2.items:
|
||||||
|
if itemwise_qty.get(ste_row.item_code) and ste_row.s_warehouse:
|
||||||
|
self.assertEquals(ste_row.qty, itemwise_qty.get(ste_row.item_code) / 2)
|
||||||
|
|
||||||
|
for ste_doc in ste_cancel_list:
|
||||||
|
ste_doc.cancel()
|
||||||
|
|
||||||
|
frappe.db.set_value("Manufacturing Settings", None, "backflush_raw_materials_based_on", "BOM")
|
||||||
|
|
||||||
def get_scrap_item_details(bom_no):
|
def get_scrap_item_details(bom_no):
|
||||||
scrap_items = {}
|
scrap_items = {}
|
||||||
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
|
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def get_columns():
|
|||||||
_("Item") + ":Link/Item:150",
|
_("Item") + ":Link/Item:150",
|
||||||
_("Description") + "::300",
|
_("Description") + "::300",
|
||||||
_("BOM Qty") + ":Float:160",
|
_("BOM Qty") + ":Float:160",
|
||||||
|
_("BOM UoM") + "::160",
|
||||||
_("Required Qty") + ":Float:120",
|
_("Required Qty") + ":Float:120",
|
||||||
_("In Stock Qty") + ":Float:120",
|
_("In Stock Qty") + ":Float:120",
|
||||||
_("Enough Parts to Build") + ":Float:200",
|
_("Enough Parts to Build") + ":Float:200",
|
||||||
@@ -32,7 +33,7 @@ def get_bom_stock(filters):
|
|||||||
bom = filters.get("bom")
|
bom = filters.get("bom")
|
||||||
|
|
||||||
table = "`tabBOM Item`"
|
table = "`tabBOM Item`"
|
||||||
qty_field = "qty"
|
qty_field = "stock_qty"
|
||||||
|
|
||||||
qty_to_produce = filters.get("qty_to_produce", 1)
|
qty_to_produce = filters.get("qty_to_produce", 1)
|
||||||
if int(qty_to_produce) <= 0:
|
if int(qty_to_produce) <= 0:
|
||||||
@@ -40,7 +41,6 @@ def get_bom_stock(filters):
|
|||||||
|
|
||||||
if filters.get("show_exploded_view"):
|
if filters.get("show_exploded_view"):
|
||||||
table = "`tabBOM Explosion Item`"
|
table = "`tabBOM Explosion Item`"
|
||||||
qty_field = "stock_qty"
|
|
||||||
|
|
||||||
if filters.get("warehouse"):
|
if filters.get("warehouse"):
|
||||||
warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
|
warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1)
|
||||||
@@ -59,6 +59,7 @@ def get_bom_stock(filters):
|
|||||||
bom_item.item_code,
|
bom_item.item_code,
|
||||||
bom_item.description ,
|
bom_item.description ,
|
||||||
bom_item.{qty_field},
|
bom_item.{qty_field},
|
||||||
|
bom_item.stock_uom,
|
||||||
bom_item.{qty_field} * {qty_to_produce} / bom.quantity,
|
bom_item.{qty_field} * {qty_to_produce} / bom.quantity,
|
||||||
sum(ledger.actual_qty) as actual_qty,
|
sum(ledger.actual_qty) as actual_qty,
|
||||||
sum(FLOOR(ledger.actual_qty / (bom_item.{qty_field} * {qty_to_produce} / bom.quantity)))
|
sum(FLOOR(ledger.actual_qty / (bom_item.{qty_field} * {qty_to_produce} / bom.quantity)))
|
||||||
|
|||||||
@@ -678,4 +678,5 @@ erpnext.patches.v12_0.update_state_code_for_daman_and_diu
|
|||||||
erpnext.patches.v12_0.rename_lost_reason_detail
|
erpnext.patches.v12_0.rename_lost_reason_detail
|
||||||
erpnext.patches.v12_0.update_leave_application_status
|
erpnext.patches.v12_0.update_leave_application_status
|
||||||
erpnext.patches.v12_0.update_payment_entry_status
|
erpnext.patches.v12_0.update_payment_entry_status
|
||||||
|
erpnext.patches.v12_0.add_transporter_address_field #2020-10-27
|
||||||
erpnext.patches.v12_0.setup_einvoice_fields #2020-12-02
|
erpnext.patches.v12_0.setup_einvoice_fields #2020-12-02
|
||||||
|
|||||||
150
erpnext/patches/v12_0/add_transporter_address_field.py
Normal file
150
erpnext/patches/v12_0/add_transporter_address_field.py
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_info',
|
||||||
|
'label': 'Transporter Info',
|
||||||
|
'fieldtype': 'Section Break',
|
||||||
|
'insert_after': 'terms',
|
||||||
|
'collapsible': 1,
|
||||||
|
'collapsible_depends_on': 'transporter',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter',
|
||||||
|
'label': 'Transporter',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'insert_after': 'transporter_info',
|
||||||
|
'options': 'Supplier',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_name',
|
||||||
|
'label': 'Transporter Name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'transporter',
|
||||||
|
'fetch_from': 'transporter.name',
|
||||||
|
'read_only': 1,
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'gst_transporter_id',
|
||||||
|
'label': 'GST Transporter ID',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'transporter_name',
|
||||||
|
'fetch_from': 'transporter.gst_transporter_id',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'driver',
|
||||||
|
'label': 'Driver',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'insert_after': 'gst_transporter_id',
|
||||||
|
'options': 'Driver',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'lr_no',
|
||||||
|
'label': 'Transport Receipt No',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'driver',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'vehicle_no',
|
||||||
|
'label': 'Vehicle No',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'lr_no',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'distance',
|
||||||
|
'label': 'Distance (in km)',
|
||||||
|
'fieldtype': 'Float',
|
||||||
|
'insert_after': 'vehicle_no',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_col_break',
|
||||||
|
'fieldtype': 'Column Break',
|
||||||
|
'insert_after': 'distance'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_address',
|
||||||
|
'label': 'Transporter Address Name',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'insert_after': 'transporter_col_break',
|
||||||
|
'options': 'Address',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_address_display',
|
||||||
|
'label': 'Transporter Address Preview',
|
||||||
|
'fieldtype': 'Small Text',
|
||||||
|
'insert_after': 'transporter_address',
|
||||||
|
'read_only': 1,
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'mode_of_transport',
|
||||||
|
'label': 'Mode of Transport',
|
||||||
|
'fieldtype': 'Select',
|
||||||
|
'options': '\nRoad\nAir\nRail\nShip',
|
||||||
|
'default': 'Road',
|
||||||
|
'insert_after': 'transporter_address_display',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'driver_name',
|
||||||
|
'label': 'Driver Name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'mode_of_transport',
|
||||||
|
'fetch_from': 'driver.full_name',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'lr_date',
|
||||||
|
'label': 'Transport Receipt Date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'insert_after': 'driver_name',
|
||||||
|
'default': 'Today',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'gst_vehicle_type',
|
||||||
|
'label': 'GST Vehicle Type',
|
||||||
|
'fieldtype': 'Select',
|
||||||
|
'options': 'Regular\nOver Dimensional Cargo (ODC)',
|
||||||
|
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
|
||||||
|
'default': 'Regular',
|
||||||
|
'insert_after': 'lr_date',
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'ewaybill',
|
||||||
|
'label': 'e-Way Bill No.',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'depends_on': 'eval:(doc.docstatus === 1)',
|
||||||
|
'allow_on_submit': 1,
|
||||||
|
'insert_after': 'tax_id',
|
||||||
|
'translatable': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
create_custom_fields({ 'Sales Invoice': fields }, update=True)
|
||||||
|
frappe.reload_doctype('Sales Invoice')
|
||||||
@@ -24,9 +24,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "reference_invoice",
|
"fieldname": "reference_invoice",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Data",
|
||||||
"label": "Reference Invoice",
|
"label": "Reference Invoice"
|
||||||
"options": "Sales Invoice"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "headers",
|
"fieldname": "headers",
|
||||||
@@ -64,7 +63,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-24 21:09:38.882866",
|
"modified": "2021-01-13 12:06:57.253111",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Regional",
|
"module": "Regional",
|
||||||
"name": "E Invoice Request Log",
|
"name": "E Invoice Request Log",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"enable",
|
"enable",
|
||||||
"section_break_2",
|
"section_break_2",
|
||||||
|
"sandbox_mode",
|
||||||
"credentials",
|
"credentials",
|
||||||
"auth_token",
|
"auth_token",
|
||||||
"token_expiry"
|
"token_expiry"
|
||||||
@@ -41,12 +42,18 @@
|
|||||||
"label": "Credentials",
|
"label": "Credentials",
|
||||||
"mandatory_depends_on": "enable",
|
"mandatory_depends_on": "enable",
|
||||||
"options": "E Invoice User"
|
"options": "E Invoice User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "sandbox_mode",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Sandbox Mode"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-22 15:34:57.280044",
|
"modified": "2021-01-13 12:04:49.449199",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Regional",
|
"module": "Regional",
|
||||||
"name": "E Invoice Settings",
|
"name": "E Invoice Settings",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
{item_list}
|
{item_list}
|
||||||
],
|
],
|
||||||
"ValDtls": {{
|
"ValDtls": {{
|
||||||
"AssVal": "{invoice_value_details.base_total}",
|
"AssVal": "{invoice_value_details.base_net_total}",
|
||||||
"CgstVal": "{invoice_value_details.total_cgst_amt}",
|
"CgstVal": "{invoice_value_details.total_cgst_amt}",
|
||||||
"SgstVal": "{invoice_value_details.total_sgst_amt}",
|
"SgstVal": "{invoice_value_details.total_sgst_amt}",
|
||||||
"IgstVal": "{invoice_value_details.total_igst_amt}",
|
"IgstVal": "{invoice_value_details.total_igst_amt}",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from frappe import _, bold
|
|||||||
from pyqrcode import create as qrcreate
|
from pyqrcode import create as qrcreate
|
||||||
from frappe.integrations.utils import make_post_request, make_get_request
|
from frappe.integrations.utils import make_post_request, make_get_request
|
||||||
from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply
|
from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply
|
||||||
from frappe.utils.data import cstr, cint, format_date, flt, time_diff_in_seconds, now_datetime, add_to_date, get_link_to_form
|
from frappe.utils.data import cstr, cint, formatdate as format_date, flt, time_diff_in_seconds, now_datetime, add_to_date, get_link_to_form
|
||||||
|
|
||||||
def validate_einvoice_fields(doc):
|
def validate_einvoice_fields(doc):
|
||||||
einvoicing_enabled = cint(frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable'))
|
einvoicing_enabled = cint(frappe.db.get_value('E Invoice Settings', 'E Invoice Settings', 'enable'))
|
||||||
@@ -193,33 +193,32 @@ def update_item_taxes(invoice, item):
|
|||||||
item[attr] = 0
|
item[attr] = 0
|
||||||
|
|
||||||
for t in invoice.taxes:
|
for t in invoice.taxes:
|
||||||
# this contains item wise tax rate & tax amount (incl. discount)
|
|
||||||
item_tax_detail = json.loads(t.item_wise_tax_detail).get(item.item_code)
|
item_tax_detail = json.loads(t.item_wise_tax_detail).get(item.item_code)
|
||||||
if t.account_head in gst_accounts_list:
|
if t.account_head in gst_accounts_list:
|
||||||
item_tax_rate = item_tax_detail[0]
|
|
||||||
# item tax amount excluding discount amount
|
|
||||||
item_tax_amount = (item_tax_rate / 100) * item.base_amount
|
|
||||||
|
|
||||||
if t.account_head in gst_accounts.cess_account:
|
if t.account_head in gst_accounts.cess_account:
|
||||||
item_tax_amount_after_discount = item_tax_detail[1]
|
|
||||||
if t.charge_type == 'On Item Quantity':
|
if t.charge_type == 'On Item Quantity':
|
||||||
item.cess_nadv_amount += abs(item_tax_amount_after_discount)
|
item.cess_nadv_amount += abs(item_tax_detail[1])
|
||||||
else:
|
else:
|
||||||
item.cess_rate += item_tax_rate
|
item.cess_rate += item_tax_detail[0]
|
||||||
item.cess_amount += abs(item_tax_amount_after_discount)
|
item.cess_amount += abs(item_tax_detail[1])
|
||||||
|
elif t.account_head in gst_accounts.igst_account:
|
||||||
for tax_type in ['igst', 'cgst', 'sgst']:
|
item.tax_rate += item_tax_detail[0]
|
||||||
if t.account_head in gst_accounts['{}_account'.format(tax_type)]:
|
item.igst_amount += abs(item_tax_detail[1])
|
||||||
item.tax_rate += item_tax_rate
|
elif t.account_head in gst_accounts.sgst_account:
|
||||||
item['{}_amount'.format(tax_type)] += abs(item_tax_amount)
|
item.tax_rate += item_tax_detail[0]
|
||||||
|
item.sgst_amount += abs(item_tax_detail[1])
|
||||||
|
elif t.account_head in gst_accounts.cgst_account:
|
||||||
|
item.tax_rate += item_tax_detail[0]
|
||||||
|
item.cgst_amount += abs(item_tax_detail[1])
|
||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def get_invoice_value_details(invoice):
|
def get_invoice_value_details(invoice):
|
||||||
invoice_value_details = frappe._dict(dict())
|
invoice_value_details = frappe._dict(dict())
|
||||||
invoice_value_details.base_total = abs(invoice.base_total)
|
invoice_value_details.base_net_total = abs(invoice.base_net_total)
|
||||||
invoice_value_details.invoice_discount_amt = invoice.discount_amount
|
invoice_value_details.invoice_discount_amt = invoice.discount_amount if invoice.discount_amount and invoice.discount_amount > 0 else 0
|
||||||
invoice_value_details.round_off = invoice.rounding_adjustment
|
# discount amount cannnot be -ve in an e-invoice, so if -ve include discount in round_off
|
||||||
|
invoice_value_details.round_off = invoice.rounding_adjustment - (invoice.discount_amount if invoice.discount_amount and invoice.discount_amount < 0 else 0)
|
||||||
invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
|
invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
|
||||||
invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
|
invoice_value_details.grand_total = abs(invoice.rounded_total) or abs(invoice.grand_total)
|
||||||
|
|
||||||
@@ -239,14 +238,15 @@ def update_invoice_taxes(invoice, invoice_value_details):
|
|||||||
for t in invoice.taxes:
|
for t in invoice.taxes:
|
||||||
if t.account_head in gst_accounts_list:
|
if t.account_head in gst_accounts_list:
|
||||||
if t.account_head in gst_accounts.cess_account:
|
if t.account_head in gst_accounts.cess_account:
|
||||||
# using after discount amt since item also uses after discount amt for cess calc
|
|
||||||
invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
|
invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount)
|
||||||
|
elif t.account_head in gst_accounts.igst_account:
|
||||||
for tax_type in ['igst', 'cgst', 'sgst']:
|
invoice_value_details.total_igst_amt += abs(t.base_tax_amount_after_discount_amount)
|
||||||
if t.account_head in gst_accounts['{}_account'.format(tax_type)]:
|
elif t.account_head in gst_accounts.sgst_account:
|
||||||
invoice_value_details['total_{}_amt'.format(tax_type)] += abs(t.base_tax_amount)
|
invoice_value_details.total_sgst_amt += abs(t.base_tax_amount_after_discount_amount)
|
||||||
|
elif t.account_head in gst_accounts.cgst_account:
|
||||||
|
invoice_value_details.total_cgst_amt += abs(t.base_tax_amount_after_discount_amount)
|
||||||
else:
|
else:
|
||||||
invoice_value_details.total_other_charges += abs(t.base_tax_amount)
|
invoice_value_details.total_other_charges += abs(t.base_tax_amount_after_discount_amount)
|
||||||
|
|
||||||
return invoice_value_details
|
return invoice_value_details
|
||||||
|
|
||||||
@@ -421,15 +421,19 @@ class RequestFailed(Exception): pass
|
|||||||
class GSPConnector():
|
class GSPConnector():
|
||||||
def __init__(self, doctype=None, docname=None):
|
def __init__(self, doctype=None, docname=None):
|
||||||
self.e_invoice_settings = frappe.get_cached_doc('E Invoice Settings')
|
self.e_invoice_settings = frappe.get_cached_doc('E Invoice Settings')
|
||||||
|
sandbox_mode = self.e_invoice_settings.sandbox_mode
|
||||||
|
|
||||||
self.invoice = frappe.get_cached_doc(doctype, docname) if doctype and docname else None
|
self.invoice = frappe.get_cached_doc(doctype, docname) if doctype and docname else None
|
||||||
self.credentials = self.get_credentials()
|
self.credentials = self.get_credentials()
|
||||||
|
|
||||||
self.base_url = 'https://gsp.adaequare.com'
|
# authenticate url is same for sandbox & live
|
||||||
self.authenticate_url = self.base_url + '/gsp/authenticate?grant_type=token'
|
self.authenticate_url = 'https://gsp.adaequare.com/gsp/authenticate?grant_type=token'
|
||||||
self.gstin_details_url = self.base_url + '/enriched/ei/api/master/gstin'
|
self.base_url = 'https://gsp.adaequare.com' if not sandbox_mode else 'https://gsp.adaequare.com/test'
|
||||||
self.generate_irn_url = self.base_url + '/enriched/ei/api/invoice'
|
|
||||||
self.irn_details_url = self.base_url + '/enriched/ei/api/invoice/irn'
|
|
||||||
self.cancel_irn_url = self.base_url + '/enriched/ei/api/invoice/cancel'
|
self.cancel_irn_url = self.base_url + '/enriched/ei/api/invoice/cancel'
|
||||||
|
self.irn_details_url = self.base_url + '/enriched/ei/api/invoice/irn'
|
||||||
|
self.generate_irn_url = self.base_url + '/enriched/ei/api/invoice'
|
||||||
|
self.gstin_details_url = self.base_url + '/enriched/ei/api/master/gstin'
|
||||||
self.cancel_ewaybill_url = self.base_url + '/enriched/ei/api/ewayapi'
|
self.cancel_ewaybill_url = self.base_url + '/enriched/ei/api/ewayapi'
|
||||||
self.generate_ewaybill_url = self.base_url + '/enriched/ei/api/ewaybill'
|
self.generate_ewaybill_url = self.base_url + '/enriched/ei/api/ewaybill'
|
||||||
|
|
||||||
@@ -765,7 +769,7 @@ class GSPConnector():
|
|||||||
|
|
||||||
_file = frappe.new_doc('File')
|
_file = frappe.new_doc('File')
|
||||||
_file.update({
|
_file.update({
|
||||||
'file_name': 'QRCode_{}.png'.format(docname),
|
'file_name': 'QRCode_{}.png'.format(docname.replace('/', '-')),
|
||||||
'attached_to_doctype': doctype,
|
'attached_to_doctype': doctype,
|
||||||
'attached_to_name': docname,
|
'attached_to_name': docname,
|
||||||
'content': 'qrcode',
|
'content': 'qrcode',
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ erpnext.setup_gst_reminder_button = (doctype) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -7,7 +7,7 @@ import frappe, os, json
|
|||||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
from frappe.permissions import add_permission, update_permission_property
|
from frappe.permissions import add_permission, update_permission_property
|
||||||
from erpnext.regional.india import states
|
from erpnext.regional.india import states
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
|
||||||
from frappe.utils import today
|
from frappe.utils import today
|
||||||
|
|
||||||
def setup(company=None, patch=True):
|
def setup(company=None, patch=True):
|
||||||
@@ -273,11 +273,21 @@ def make_custom_fields(update=True):
|
|||||||
'options': 'Supplier',
|
'options': 'Supplier',
|
||||||
'print_hide': 1
|
'print_hide': 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_name',
|
||||||
|
'label': 'Transporter Name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'insert_after': 'transporter',
|
||||||
|
'fetch_from': 'transporter.name',
|
||||||
|
'read_only': 1,
|
||||||
|
'print_hide': 1,
|
||||||
|
'translatable': 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'fieldname': 'gst_transporter_id',
|
'fieldname': 'gst_transporter_id',
|
||||||
'label': 'GST Transporter ID',
|
'label': 'GST Transporter ID',
|
||||||
'fieldtype': 'Data',
|
'fieldtype': 'Data',
|
||||||
'insert_after': 'transporter',
|
'insert_after': 'transporter_name',
|
||||||
'fetch_from': 'transporter.gst_transporter_id',
|
'fetch_from': 'transporter.gst_transporter_id',
|
||||||
'print_hide': 1,
|
'print_hide': 1,
|
||||||
'translatable': 0
|
'translatable': 0
|
||||||
@@ -319,11 +329,18 @@ def make_custom_fields(update=True):
|
|||||||
'insert_after': 'distance'
|
'insert_after': 'distance'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'fieldname': 'transporter_name',
|
'fieldname': 'transporter_address',
|
||||||
'label': 'Transporter Name',
|
'label': 'Transporter Address Name',
|
||||||
'fieldtype': 'Data',
|
'fieldtype': 'Link',
|
||||||
'insert_after': 'transporter_col_break',
|
'insert_after': 'transporter_col_break',
|
||||||
'fetch_from': 'transporter.name',
|
'options': 'Address',
|
||||||
|
'print_hide': 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'fieldname': 'transporter_address_display',
|
||||||
|
'label': 'Transporter Address Preview',
|
||||||
|
'fieldtype': 'Small Text',
|
||||||
|
'insert_after': 'transporter_address',
|
||||||
'read_only': 1,
|
'read_only': 1,
|
||||||
'print_hide': 1,
|
'print_hide': 1,
|
||||||
'translatable': 0
|
'translatable': 0
|
||||||
@@ -333,7 +350,8 @@ def make_custom_fields(update=True):
|
|||||||
'label': 'Mode of Transport',
|
'label': 'Mode of Transport',
|
||||||
'fieldtype': 'Select',
|
'fieldtype': 'Select',
|
||||||
'options': '\nRoad\nAir\nRail\nShip',
|
'options': '\nRoad\nAir\nRail\nShip',
|
||||||
'insert_after': 'transporter_name',
|
'default': 'Road',
|
||||||
|
'insert_after': 'transporter_address_display',
|
||||||
'print_hide': 1,
|
'print_hide': 1,
|
||||||
'translatable': 0
|
'translatable': 0
|
||||||
},
|
},
|
||||||
@@ -567,13 +585,18 @@ def set_salary_components(docs):
|
|||||||
|
|
||||||
def set_tax_withholding_category(company):
|
def set_tax_withholding_category(company):
|
||||||
accounts = []
|
accounts = []
|
||||||
|
fiscal_year = None
|
||||||
abbr = frappe.get_value("Company", company, "abbr")
|
abbr = frappe.get_value("Company", company, "abbr")
|
||||||
tds_account = frappe.get_value("Account", 'TDS Payable - {0}'.format(abbr), 'name')
|
tds_account = frappe.get_value("Account", 'TDS Payable - {0}'.format(abbr), 'name')
|
||||||
|
|
||||||
if company and tds_account:
|
if company and tds_account:
|
||||||
accounts = [dict(company=company, account=tds_account)]
|
accounts = [dict(company=company, account=tds_account)]
|
||||||
|
|
||||||
fiscal_year = get_fiscal_year(today(), company=company)[0]
|
try:
|
||||||
|
fiscal_year = get_fiscal_year(today(), verbose=0, company=company)[0]
|
||||||
|
except FiscalYearError:
|
||||||
|
pass
|
||||||
|
|
||||||
docs = get_tds_details(accounts, fiscal_year)
|
docs = get_tds_details(accounts, fiscal_year)
|
||||||
|
|
||||||
for d in docs:
|
for d in docs:
|
||||||
@@ -588,11 +611,14 @@ def set_tax_withholding_category(company):
|
|||||||
if accounts:
|
if accounts:
|
||||||
doc.append("accounts", accounts[0])
|
doc.append("accounts", accounts[0])
|
||||||
|
|
||||||
# if fiscal year don't match with any of the already entered data, append rate row
|
if fiscal_year:
|
||||||
fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
|
# if fiscal year don't match with any of the already entered data, append rate row
|
||||||
if not fy_exist:
|
fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
|
||||||
doc.append("rates", d.get('rates')[0])
|
if not fy_exist:
|
||||||
|
doc.append("rates", d.get('rates')[0])
|
||||||
|
|
||||||
|
doc.flags.ignore_permissions = True
|
||||||
|
doc.flags.ignore_mandatory = True
|
||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
def set_tds_account(docs, company):
|
def set_tds_account(docs, company):
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from erpnext.regional.india import number_state_mapping
|
|||||||
from six import string_types
|
from six import string_types
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
|
from frappe.contacts.doctype.address.address import get_address_display
|
||||||
from frappe.model.utils import get_fetch_values
|
from frappe.model.utils import get_fetch_values
|
||||||
|
|
||||||
def validate_gstin_for_india(doc, method):
|
def validate_gstin_for_india(doc, method):
|
||||||
@@ -93,8 +94,7 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
|
|||||||
total += digit
|
total += digit
|
||||||
factor = 2 if factor == 1 else 1
|
factor = 2 if factor == 1 else 1
|
||||||
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
|
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
|
||||||
frappe.throw(_("""Invalid {0}! The check digit validation has failed.
|
frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label))
|
||||||
Please ensure you've typed the {0} correctly.""").format(label))
|
|
||||||
|
|
||||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||||
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||||
@@ -138,6 +138,30 @@ def get_itemised_tax_breakup_data(doc, account_wise=False):
|
|||||||
def set_place_of_supply(doc, method=None):
|
def set_place_of_supply(doc, method=None):
|
||||||
doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
|
doc.place_of_supply = get_place_of_supply(doc, doc.doctype)
|
||||||
|
|
||||||
|
def set_transporter_address(doc, method=None):
|
||||||
|
country = frappe.get_cached_value('Company', doc.company, 'country')
|
||||||
|
if country != 'India':
|
||||||
|
return
|
||||||
|
|
||||||
|
if doc.get("transporter_address"):
|
||||||
|
# once supplier is set, address can be selected from multiple transporter addresses
|
||||||
|
doc.transporter_address_display = get_address_display(doc.get("transporter_address"))
|
||||||
|
return
|
||||||
|
|
||||||
|
transporter_address = frappe.db.get_value("Dynamic Link", {
|
||||||
|
'link_doctype': 'Supplier',
|
||||||
|
'link_name': doc.get('transporter'),
|
||||||
|
'parenttype': 'Address'
|
||||||
|
}, "parent")
|
||||||
|
|
||||||
|
if not transporter_address:
|
||||||
|
doc.transporter_address = ""
|
||||||
|
doc.transporter_address_display = ""
|
||||||
|
return
|
||||||
|
|
||||||
|
doc.transporter_address = transporter_address
|
||||||
|
doc.transporter_address_display = get_address_display(transporter_address)
|
||||||
|
|
||||||
# don't remove this function it is used in tests
|
# don't remove this function it is used in tests
|
||||||
def test_method():
|
def test_method():
|
||||||
'''test function'''
|
'''test function'''
|
||||||
|
|||||||
@@ -255,15 +255,16 @@ class Gstr1Report(object):
|
|||||||
|
|
||||||
for item_code, tax_amounts in item_wise_tax_detail.items():
|
for item_code, tax_amounts in item_wise_tax_detail.items():
|
||||||
tax_rate = tax_amounts[0]
|
tax_rate = tax_amounts[0]
|
||||||
if cgst_or_sgst:
|
if tax_rate:
|
||||||
tax_rate *= 2
|
if cgst_or_sgst:
|
||||||
if parent not in self.cgst_sgst_invoices:
|
tax_rate *= 2
|
||||||
self.cgst_sgst_invoices.append(parent)
|
if parent not in self.cgst_sgst_invoices:
|
||||||
|
self.cgst_sgst_invoices.append(parent)
|
||||||
|
|
||||||
rate_based_dict = self.items_based_on_tax_rate\
|
rate_based_dict = self.items_based_on_tax_rate\
|
||||||
.setdefault(parent, {}).setdefault(tax_rate, [])
|
.setdefault(parent, {}).setdefault(tax_rate, [])
|
||||||
if item_code not in rate_based_dict:
|
if item_code not in rate_based_dict:
|
||||||
rate_based_dict.append(item_code)
|
rate_based_dict.append(item_code)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
if unidentified_gst_accounts:
|
if unidentified_gst_accounts:
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
var me = this;
|
var me = this;
|
||||||
if (this.frm.doc.customer) {
|
if (this.frm.doc.customer) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details",
|
method: "erpnext.accounts.doctype.loyalty_program.loyalty_program.get_loyalty_program_details_with_points",
|
||||||
args: {
|
args: {
|
||||||
"customer": me.frm.doc.customer,
|
"customer": me.frm.doc.customer,
|
||||||
"expiry_date": me.frm.doc.posting_date,
|
"expiry_date": me.frm.doc.posting_date,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ from frappe.utils.nestedset import get_descendants_of
|
|||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
filters = frappe._dict(filters or {})
|
filters = frappe._dict(filters or {})
|
||||||
if filters.from_date > filters.to_date:
|
if filters.from_date > filters.to_date:
|
||||||
frappe.throw(_('From Date cannot be greater than To Date'))
|
frappe.throw(_("From Date cannot be greater than To Date"))
|
||||||
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
data = get_data(filters)
|
data = get_data(filters)
|
||||||
return columns, data
|
return columns, data
|
||||||
@@ -145,14 +145,16 @@ def get_data(filters):
|
|||||||
company_list.append(filters.get("company"))
|
company_list.append(filters.get("company"))
|
||||||
|
|
||||||
customer_details = get_customer_details()
|
customer_details = get_customer_details()
|
||||||
|
item_details = get_item_details()
|
||||||
sales_order_records = get_sales_order_details(company_list, filters)
|
sales_order_records = get_sales_order_details(company_list, filters)
|
||||||
|
|
||||||
for record in sales_order_records:
|
for record in sales_order_records:
|
||||||
customer_record = customer_details.get(record.customer)
|
customer_record = customer_details.get(record.customer)
|
||||||
|
item_record = item_details.get(record.item_code)
|
||||||
row = {
|
row = {
|
||||||
"item_code": record.item_code,
|
"item_code": record.item_code,
|
||||||
"item_name": record.item_name,
|
"item_name": item_record.item_name,
|
||||||
"item_group": record.item_group,
|
"item_group": item_record.item_group,
|
||||||
"description": record.description,
|
"description": record.description,
|
||||||
"quantity": record.qty,
|
"quantity": record.qty,
|
||||||
"uom": record.uom,
|
"uom": record.uom,
|
||||||
@@ -187,8 +189,8 @@ def get_conditions(filters):
|
|||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_customer_details():
|
def get_customer_details():
|
||||||
details = frappe.get_all('Customer',
|
details = frappe.get_all("Customer",
|
||||||
fields=['name', 'customer_name', "customer_group"])
|
fields=["name", "customer_name", "customer_group"])
|
||||||
customer_details = {}
|
customer_details = {}
|
||||||
for d in details:
|
for d in details:
|
||||||
customer_details.setdefault(d.name, frappe._dict({
|
customer_details.setdefault(d.name, frappe._dict({
|
||||||
@@ -197,15 +199,25 @@ def get_customer_details():
|
|||||||
}))
|
}))
|
||||||
return customer_details
|
return customer_details
|
||||||
|
|
||||||
|
def get_item_details():
|
||||||
|
details = frappe.db.get_all("Item",
|
||||||
|
fields=["item_code", "item_name", "item_group"])
|
||||||
|
item_details = {}
|
||||||
|
for d in details:
|
||||||
|
item_details.setdefault(d.item_code, frappe._dict({
|
||||||
|
"item_name": d.item_name,
|
||||||
|
"item_group": d.item_group
|
||||||
|
}))
|
||||||
|
return item_details
|
||||||
|
|
||||||
def get_sales_order_details(company_list, filters):
|
def get_sales_order_details(company_list, filters):
|
||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
so_item.item_code, so_item.item_name, so_item.item_group,
|
so_item.item_code, so_item.description, so_item.qty,
|
||||||
so_item.description, so_item.qty, so_item.uom,
|
so_item.uom, so_item.base_rate, so_item.base_amount,
|
||||||
so_item.base_rate, so_item.base_amount, so.name,
|
so.name, so.transaction_date, so.customer,so.territory,
|
||||||
so.transaction_date, so.customer, so.territory,
|
|
||||||
so.project, so_item.delivered_qty,
|
so.project, so_item.delivered_qty,
|
||||||
so_item.billed_amt, so.company
|
so_item.billed_amt, so.company
|
||||||
FROM
|
FROM
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ def delete_company_transactions(company_name):
|
|||||||
tabDocField where fieldtype='Link' and options='Company'"""):
|
tabDocField where fieldtype='Link' and options='Company'"""):
|
||||||
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
|
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
|
||||||
"Party Account", "Employee", "Sales Taxes and Charges Template",
|
"Party Account", "Employee", "Sales Taxes and Charges Template",
|
||||||
"Purchase Taxes and Charges Template", "POS Profile", 'BOM'):
|
"Purchase Taxes and Charges Template", "POS Profile", 'BOM',
|
||||||
|
"Item default", "Customer", "Supplier"):
|
||||||
delete_for_doctype(doctype, company_name)
|
delete_for_doctype(doctype, company_name)
|
||||||
|
|
||||||
# reset company values
|
# reset company values
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
"basic_rate": 1.0
|
"basic_rate": 1.0
|
||||||
})
|
})
|
||||||
se_doc.get("items")[1].update({
|
se_doc.get("items")[1].update({
|
||||||
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
"qty": 3.0,
|
"qty": 3.0,
|
||||||
"transfer_qty": 3.0,
|
"transfer_qty": 3.0,
|
||||||
"s_warehouse": "_Test Warehouse 1 - _TC",
|
"s_warehouse": "_Test Warehouse 1 - _TC",
|
||||||
@@ -537,7 +538,7 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
|
|
||||||
mr = make_material_request(item_code='_Test FG Item', material_request_type='Manufacture',
|
mr = make_material_request(item_code='_Test FG Item', material_request_type='Manufacture',
|
||||||
uom="_Test UOM 1", conversion_factor=12)
|
uom="_Test UOM 1", conversion_factor=12)
|
||||||
|
|
||||||
requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
|
requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
|
||||||
|
|
||||||
self.assertEqual(requested_qty, existing_requested_qty + 120)
|
self.assertEqual(requested_qty, existing_requested_qty + 120)
|
||||||
|
|||||||
@@ -52,10 +52,24 @@ class QualityInspection(Document):
|
|||||||
doctype = 'Stock Entry Detail'
|
doctype = 'Stock Entry Detail'
|
||||||
|
|
||||||
if self.reference_type and self.reference_name:
|
if self.reference_type and self.reference_name:
|
||||||
frappe.db.sql("""update `tab{child_doc}` t1, `tab{parent_doc}` t2
|
conditions = ""
|
||||||
set t1.quality_inspection = %s, t2.modified = %s
|
if self.batch_no and self.docstatus == 1:
|
||||||
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name"""
|
conditions += " and t1.batch_no = '%s'"%(self.batch_no)
|
||||||
.format(parent_doc=self.reference_type, child_doc=doctype),
|
|
||||||
|
if self.docstatus == 2: # if cancel, then remove qi link wherever same name
|
||||||
|
conditions += " and t1.quality_inspection = '%s'"%(self.name)
|
||||||
|
|
||||||
|
frappe.db.sql("""
|
||||||
|
UPDATE
|
||||||
|
`tab{child_doc}` t1, `tab{parent_doc}` t2
|
||||||
|
SET
|
||||||
|
t1.quality_inspection = %s, t2.modified = %s
|
||||||
|
WHERE
|
||||||
|
t1.parent = %s
|
||||||
|
and t1.item_code = %s
|
||||||
|
and t1.parent = t2.name
|
||||||
|
{conditions}
|
||||||
|
""".format(parent_doc=self.reference_type, child_doc=doctype, conditions=conditions),
|
||||||
(quality_inspection, self.modified, self.reference_name, self.item_code))
|
(quality_inspection, self.modified, self.reference_name, self.item_code))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -488,6 +488,8 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
if self.purpose in ["Manufacture", "Repack"]:
|
if self.purpose in ["Manufacture", "Repack"]:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
|
if d.set_basic_rate_manually: continue
|
||||||
|
|
||||||
if (d.transfer_qty and (d.bom_no or d.t_warehouse)
|
if (d.transfer_qty and (d.bom_no or d.t_warehouse)
|
||||||
and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
|
and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
|
||||||
|
|
||||||
@@ -499,7 +501,7 @@ class StockEntry(StockController):
|
|||||||
if raw_material_cost and self.purpose == "Manufacture":
|
if raw_material_cost and self.purpose == "Manufacture":
|
||||||
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
||||||
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
||||||
elif self.purpose == "Repack" and total_fg_qty and not d.set_basic_rate_manually:
|
elif self.purpose == "Repack" and total_fg_qty:
|
||||||
d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
|
d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
|
||||||
d.basic_amount = d.basic_rate * flt(d.qty)
|
d.basic_amount = d.basic_rate * flt(d.qty)
|
||||||
|
|
||||||
@@ -1010,7 +1012,7 @@ class StockEntry(StockController):
|
|||||||
wo = frappe.get_doc("Work Order", self.work_order)
|
wo = frappe.get_doc("Work Order", self.work_order)
|
||||||
wo_items = frappe.get_all('Work Order Item',
|
wo_items = frappe.get_all('Work Order Item',
|
||||||
filters={'parent': self.work_order},
|
filters={'parent': self.work_order},
|
||||||
fields=["item_code", "required_qty", "consumed_qty", "transferred_qty"]
|
fields=["item_code", "required_qty", "consumed_qty", "transferred_qty", "source_warehouse"]
|
||||||
)
|
)
|
||||||
|
|
||||||
work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
|
work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
|
||||||
@@ -1028,9 +1030,13 @@ class StockEntry(StockController):
|
|||||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||||
|
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
|
from_warehouse = wo.wip_warehouse
|
||||||
|
if wo.skip_transfer and not wo.from_wip_warehouse:
|
||||||
|
from_warehouse = item.source_warehouse
|
||||||
|
|
||||||
self.add_to_stock_entry_detail({
|
self.add_to_stock_entry_detail({
|
||||||
item.item_code: {
|
item.item_code: {
|
||||||
"from_warehouse": wo.wip_warehouse,
|
"from_warehouse": from_warehouse,
|
||||||
"to_warehouse": "",
|
"to_warehouse": "",
|
||||||
"qty": qty,
|
"qty": qty,
|
||||||
"item_name": item.item_name,
|
"item_name": item.item_name,
|
||||||
@@ -1109,7 +1115,10 @@ class StockEntry(StockController):
|
|||||||
else:
|
else:
|
||||||
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
||||||
else:
|
else:
|
||||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
if self.flags.backflush_based_on == "Material Transferred for Manufacture":
|
||||||
|
qty = (item.qty/trans_qty) * flt(self.fg_completed_qty)
|
||||||
|
else:
|
||||||
|
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||||
|
|
||||||
elif backflushed_materials.get(item.item_code):
|
elif backflushed_materials.get(item.item_code):
|
||||||
for d in backflushed_materials.get(item.item_code):
|
for d in backflushed_materials.get(item.item_code):
|
||||||
@@ -1117,7 +1126,8 @@ class StockEntry(StockController):
|
|||||||
if (qty > req_qty):
|
if (qty > req_qty):
|
||||||
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
||||||
|
|
||||||
if consumed_qty:
|
if consumed_qty and frappe.db.get_single_value("Manufacturing Settings",
|
||||||
|
"material_consumption"):
|
||||||
qty -= consumed_qty
|
qty -= consumed_qty
|
||||||
|
|
||||||
if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
|
if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
|
||||||
@@ -1241,9 +1251,8 @@ class StockEntry(StockController):
|
|||||||
mreq_item = frappe.db.get_value("Material Request Item",
|
mreq_item = frappe.db.get_value("Material Request Item",
|
||||||
{"name": item.material_request_item, "parent": item.material_request},
|
{"name": item.material_request_item, "parent": item.material_request},
|
||||||
["item_code", "warehouse", "idx"], as_dict=True)
|
["item_code", "warehouse", "idx"], as_dict=True)
|
||||||
if mreq_item.item_code != item.item_code or \
|
if mreq_item.item_code != item.item_code:
|
||||||
mreq_item.warehouse != (item.s_warehouse if self.purpose== "Material Issue" else item.t_warehouse):
|
frappe.throw(_("Item for row {0} does not match Material Request").format(item.idx),
|
||||||
frappe.throw(_("Item or Warehouse for row {0} does not match Material Request").format(item.idx),
|
|
||||||
frappe.MappingMismatchError)
|
frappe.MappingMismatchError)
|
||||||
|
|
||||||
def validate_batch(self):
|
def validate_batch(self):
|
||||||
|
|||||||
@@ -494,7 +494,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:parent.purpose===\"Repack\" && doc.t_warehouse",
|
"depends_on": "eval:in_list([\"Repack\", \"Manufacture\"], parent.purpose) && doc.t_warehouse",
|
||||||
"fieldname": "set_basic_rate_manually",
|
"fieldname": "set_basic_rate_manually",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Set Basic Rate Manually"
|
"label": "Set Basic Rate Manually"
|
||||||
@@ -502,7 +502,7 @@
|
|||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2020-09-04 12:12:35.668198",
|
"modified": "2021-01-05 15:05:04.891447",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Entry Detail",
|
"name": "Stock Entry Detail",
|
||||||
|
|||||||
Reference in New Issue
Block a user