Merge branch 'hotfix' of https://github.com/frappe/erpnext into bom-item
This commit is contained in:
commit
56b52d43e6
@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '11.1.7'
|
||||
__version__ = '11.1.10'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe, erpnext, json
|
||||
from frappe import _, scrub, ValidationError
|
||||
from frappe.utils import flt, comma_or, nowdate, getdate
|
||||
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
|
||||
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on, get_allow_cost_center_in_entry_of_bs_account
|
||||
from erpnext.accounts.party import get_party_account
|
||||
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
@ -564,8 +564,8 @@ def get_outstanding_reference_documents(args):
|
||||
.format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"]))
|
||||
|
||||
# Add cost center condition
|
||||
if args.get("cost_center"):
|
||||
condition += " and cost_center='%s'" % args.get("cost_center")
|
||||
if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account():
|
||||
condition += " and cost_center='%s'" % args.get("cost_center")
|
||||
|
||||
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||
args.get("party_account"), condition=condition)
|
||||
|
@ -201,7 +201,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
get_query: function() {
|
||||
var filters = {
|
||||
docstatus: 1,
|
||||
company: me.frm.doc.company
|
||||
company: me.frm.doc.company,
|
||||
is_return: 0
|
||||
};
|
||||
if(me.frm.doc.customer) filters["customer"] = me.frm.doc.customer;
|
||||
return {
|
||||
|
@ -24,7 +24,6 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente
|
||||
from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
|
||||
get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points
|
||||
from erpnext.accounts.deferred_revenue import validate_service_stop_date
|
||||
from erpnext.controllers.accounts_controller import on_submit_regional, on_cancel_regional
|
||||
|
||||
from erpnext.healthcare.utils import manage_invoice_submit_cancel
|
||||
|
||||
@ -199,8 +198,6 @@ class SalesInvoice(SellingController):
|
||||
if "Healthcare" in active_domains:
|
||||
manage_invoice_submit_cancel(self, "on_submit")
|
||||
|
||||
on_submit_regional(self)
|
||||
|
||||
def validate_pos_paid_amount(self):
|
||||
if len(self.payments) == 0 and self.is_pos:
|
||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||
@ -256,8 +253,6 @@ class SalesInvoice(SellingController):
|
||||
if "Healthcare" in active_domains:
|
||||
manage_invoice_submit_cancel(self, "on_cancel")
|
||||
|
||||
on_cancel_regional(self)
|
||||
|
||||
def update_status_updater_args(self):
|
||||
if cint(self.update_stock):
|
||||
self.status_updater.extend([{
|
||||
@ -1017,9 +1012,10 @@ class SalesInvoice(SellingController):
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice")
|
||||
if sales_invoice and self.name != sales_invoice:
|
||||
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}".format(
|
||||
serial_no, sales_invoice
|
||||
)))
|
||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company")
|
||||
if sales_invoice_company == self.company:
|
||||
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
|
||||
.format(serial_no, sales_invoice)))
|
||||
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
|
@ -270,7 +270,7 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
for period in period_list:
|
||||
total_row.setdefault(period.key, 0.0)
|
||||
total_row[period.key] += row.get(period.key, 0.0)
|
||||
row[period.key] = 0.0
|
||||
row[period.key] = row.get(period.key, 0.0)
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += flt(row["total"])
|
||||
|
@ -135,9 +135,9 @@ class GrossProfitGenerator(object):
|
||||
row.buying_rate, row.base_rate = 0.0, 0.0
|
||||
|
||||
# calculate gross profit
|
||||
row.gross_profit = row.base_amount - row.buying_amount
|
||||
row.gross_profit = flt(row.base_amount - row.buying_amount, 3)
|
||||
if row.base_amount:
|
||||
row.gross_profit_percent = (row.gross_profit / row.base_amount) * 100.0
|
||||
row.gross_profit_percent = flt((row.gross_profit / row.base_amount) * 100.0, 3)
|
||||
else:
|
||||
row.gross_profit_percent = 0.0
|
||||
|
||||
@ -174,8 +174,8 @@ class GrossProfitGenerator(object):
|
||||
self.grouped_data.append(row)
|
||||
|
||||
def set_average_rate(self, new_row):
|
||||
new_row.gross_profit = new_row.base_amount - new_row.buying_amount
|
||||
new_row.gross_profit_percent = ((new_row.gross_profit / new_row.base_amount) * 100.0) \
|
||||
new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount,3)
|
||||
new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0),3) \
|
||||
if new_row.base_amount else 0
|
||||
new_row.buying_rate = (new_row.buying_amount / new_row.qty) if new_row.qty else 0
|
||||
new_row.base_rate = (new_row.base_amount / new_row.qty) if new_row.qty else 0
|
||||
|
@ -1138,11 +1138,3 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
|
||||
@erpnext.allow_regional
|
||||
def validate_regional(doc):
|
||||
pass
|
||||
|
||||
@erpnext.allow_regional
|
||||
def on_submit_regional(doc):
|
||||
pass
|
||||
|
||||
@erpnext.allow_regional
|
||||
def on_cancel_regional(doc):
|
||||
pass
|
||||
|
@ -202,7 +202,8 @@ doc_events = {
|
||||
"validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
|
||||
},
|
||||
"Sales Invoice": {
|
||||
"on_submit": "erpnext.regional.france.utils.create_transaction_log",
|
||||
"on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
|
||||
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
|
||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
||||
},
|
||||
"Payment Entry": {
|
||||
@ -210,7 +211,7 @@ doc_events = {
|
||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
||||
},
|
||||
'Address': {
|
||||
'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.validate_address']
|
||||
'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code']
|
||||
},
|
||||
('Sales Invoice', 'Purchase Invoice', 'Delivery Note'): {
|
||||
'validate': 'erpnext.regional.india.utils.set_place_of_supply'
|
||||
@ -305,7 +306,5 @@ regional_overrides = {
|
||||
'Italy': {
|
||||
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.italy.utils.update_itemised_tax_data',
|
||||
'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.italy.utils.sales_invoice_validate',
|
||||
'erpnext.controllers.accounts_controller.on_submit_regional': 'erpnext.regional.italy.utils.sales_invoice_on_submit',
|
||||
'erpnext.controllers.accounts_controller.on_cancel_regional': 'erpnext.regional.italy.utils.sales_invoice_on_cancel'
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +487,6 @@ def get_events(start, end, filters=None):
|
||||
|
||||
add_block_dates(events, start, end, employee, company)
|
||||
add_holidays(events, start, end, employee, company)
|
||||
|
||||
return events
|
||||
|
||||
def add_department_leaves(events, start, end, employee, company):
|
||||
@ -500,10 +499,22 @@ def add_department_leaves(events, start, end, employee, company):
|
||||
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
|
||||
and company=%s""", (department, company))
|
||||
|
||||
match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
add_leaves(events, start, end, match_conditions=match_conditions)
|
||||
filter_conditions = "employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
add_leaves(events, start, end, filter_conditions=filter_conditions)
|
||||
|
||||
def add_leaves(events, start, end, filter_conditions=None):
|
||||
conditions = []
|
||||
|
||||
if filter_conditions:
|
||||
conditions.append(filter_conditions)
|
||||
|
||||
if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("Leave Application")
|
||||
|
||||
if match_conditions:
|
||||
conditions.append(match_conditions)
|
||||
|
||||
def add_leaves(events, start, end, match_conditions=None):
|
||||
query = """select name, from_date, to_date, employee_name, half_day,
|
||||
status, employee, docstatus
|
||||
from `tabLeave Application` where
|
||||
@ -511,8 +522,8 @@ def add_leaves(events, start, end, match_conditions=None):
|
||||
and docstatus < 2
|
||||
and status!="Rejected" """
|
||||
|
||||
if match_conditions:
|
||||
query += match_conditions
|
||||
if conditions:
|
||||
query += ' and ' + ' and '.join(conditions)
|
||||
|
||||
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
||||
e = {
|
||||
|
@ -41,12 +41,19 @@ class MaintenanceVisit(TransactionBase):
|
||||
work_done = nm and nm[0][3] or ''
|
||||
else:
|
||||
status = 'Open'
|
||||
mntc_date = ''
|
||||
service_person = ''
|
||||
work_done = ''
|
||||
mntc_date = None
|
||||
service_person = None
|
||||
work_done = None
|
||||
|
||||
frappe.db.sql("update `tabWarranty Claim` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname))
|
||||
wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname)
|
||||
wc_doc.update({
|
||||
'resolution_date': mntc_date,
|
||||
'resolved_by': service_person,
|
||||
'resolution_details': work_done,
|
||||
'status': status
|
||||
})
|
||||
|
||||
wc_doc.db_update()
|
||||
|
||||
def check_if_last_visit(self):
|
||||
"""check if last maintenance visit against same sales order/ Warranty Claim"""
|
||||
|
@ -8,21 +8,21 @@ import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
company = frappe.get_all('Company', filters = {'country': 'Italy'})
|
||||
if not company:
|
||||
return
|
||||
frappe.reload_doc('regional', 'report', 'electronic_invoice_register')
|
||||
make_custom_fields()
|
||||
setup_report()
|
||||
|
||||
make_custom_fields()
|
||||
setup_report()
|
||||
# Set state codes
|
||||
condition = ""
|
||||
for state, code in state_codes.items():
|
||||
condition += " when '{0}' then '{1}'".format(frappe.db.escape(state), frappe.db.escape(code))
|
||||
|
||||
# Set state codes
|
||||
condition = ""
|
||||
for state, code in state_codes.items():
|
||||
condition += " when '{0}' then '{1}'".format(frappe.db.escape(state), frappe.db.escape(code))
|
||||
|
||||
if condition:
|
||||
frappe.db.sql("""
|
||||
UPDATE tabAddress set state_code = (case state {condition} end)
|
||||
WHERE country in ('Italy', 'Italia', 'Italian Republic', 'Repubblica Italiana')
|
||||
""".format(condition=condition))
|
||||
if condition:
|
||||
frappe.db.sql("""
|
||||
UPDATE tabAddress set state_code = (case state {condition} end)
|
||||
WHERE country in ('Italy', 'Italia', 'Italian Republic', 'Repubblica Italiana')
|
||||
""".format(condition=condition))
|
||||
|
@ -255,11 +255,16 @@ $.extend(erpnext.utils, {
|
||||
// get valid options for tree based on user permission & locals dict
|
||||
let unscrub_option = frappe.model.unscrub(option);
|
||||
let user_permission = frappe.defaults.get_user_permissions();
|
||||
let options;
|
||||
|
||||
if(user_permission && user_permission[unscrub_option]) {
|
||||
return user_permission[unscrub_option].map(perm => perm.doc);
|
||||
options = user_permission[unscrub_option].map(perm => perm.doc);
|
||||
} else {
|
||||
return $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort();
|
||||
options = $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort();
|
||||
}
|
||||
|
||||
// filter unique values, as there may be multiple user permissions for any value
|
||||
return options.filter((value, index, self) => self.indexOf(value) === index);
|
||||
},
|
||||
get_tree_default: function(option) {
|
||||
// set default for a field based on user permission
|
||||
|
@ -10,12 +10,12 @@ from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons, mode_of_payment_codes, vat_collectability_options
|
||||
|
||||
def setup(company=None, patch=True):
|
||||
make_custom_fields()
|
||||
setup_report()
|
||||
make_custom_fields()
|
||||
setup_report()
|
||||
|
||||
def make_custom_fields(update=True):
|
||||
invoice_item_fields = [
|
||||
dict(fieldname='tax_rate', label='Tax Rate',
|
||||
invoice_item_fields = [
|
||||
dict(fieldname='tax_rate', label='Tax Rate',
|
||||
fieldtype='Float', insert_after='description',
|
||||
print_hide=1, hidden=1, read_only=1),
|
||||
dict(fieldname='tax_amount', label='Tax Amount',
|
||||
@ -24,135 +24,135 @@ def make_custom_fields(update=True):
|
||||
dict(fieldname='total_amount', label='Total Amount',
|
||||
fieldtype='Currency', insert_after='tax_amount',
|
||||
print_hide=1, hidden=1, read_only=1, options="currency")
|
||||
]
|
||||
]
|
||||
|
||||
custom_fields = {
|
||||
'Company': [
|
||||
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
||||
fieldtype='Section Break', insert_after='date_of_establishment', print_hide=1),
|
||||
dict(fieldname='fiscal_regime', label='Fiscal Regime',
|
||||
fieldtype='Select', insert_after='sb_e_invoicing', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))),
|
||||
dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='fiscal_regime', print_hide=1,
|
||||
description=_("Applicable if the company is an Individual or a Proprietorship")),
|
||||
dict(fieldname='vat_collectability', label='VAT Collectability',
|
||||
fieldtype='Select', insert_after='fiscal_code', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options))),
|
||||
dict(fieldname='cb_e_invoicing1', fieldtype='Column Break', insert_after='vat_collectability', print_hide=1),
|
||||
dict(fieldname='registrar_office_province', label='Province of the Registrar Office',
|
||||
fieldtype='Data', insert_after='cb_e_invoicing1', print_hide=1, length=2),
|
||||
dict(fieldname='registration_number', label='Registration Number',
|
||||
fieldtype='Data', insert_after='registrar_office_province', print_hide=1, length=20),
|
||||
dict(fieldname='share_capital_amount', label='Share Capital',
|
||||
fieldtype='Currency', insert_after='registration_number', print_hide=1,
|
||||
description=_('Applicable if the company is SpA, SApA or SRL')),
|
||||
dict(fieldname='no_of_members', label='No of Members',
|
||||
fieldtype='Select', insert_after='share_capital_amount', print_hide=1,
|
||||
options="\nSU-Socio Unico\nSM-Piu Soci", description=_("Applicable if the company is a limited liability company")),
|
||||
dict(fieldname='liquidation_state', label='Liquidation State',
|
||||
fieldtype='Select', insert_after='no_of_members', print_hide=1,
|
||||
options="\nLS-In Liquidazione\nLN-Non in Liquidazione")
|
||||
],
|
||||
'Sales Taxes and Charges': [
|
||||
dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason',
|
||||
fieldtype='Select', insert_after='included_in_print_rate', print_hide=1,
|
||||
depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0',
|
||||
options="\n" + "\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))),
|
||||
dict(fieldname='tax_exemption_law', label='Tax Exempt Under',
|
||||
fieldtype='Text', insert_after='tax_exemption_reason', print_hide=1,
|
||||
depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0')
|
||||
],
|
||||
'Customer': [
|
||||
dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1),
|
||||
dict(fieldname='recipient_code', label='Recipient Code',
|
||||
fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"),
|
||||
dict(fieldname='pec', label='Recipient PEC',
|
||||
fieldtype='Data', insert_after='fiscal_code', print_hide=1),
|
||||
dict(fieldname='is_public_administration', label='Is Public Administration',
|
||||
fieldtype='Check', insert_after='is_internal_customer', print_hide=1,
|
||||
description=_("Set this if the customer is a Public Administration company."),
|
||||
depends_on='eval:doc.customer_type=="Company"'),
|
||||
dict(fieldname='first_name', label='First Name', fieldtype='Data',
|
||||
insert_after='salutation', print_hide=1, depends_on='eval:doc.customer_type!="Company"'),
|
||||
dict(fieldname='last_name', label='Last Name', fieldtype='Data',
|
||||
insert_after='first_name', print_hide=1, depends_on='eval:doc.customer_type!="Company"')
|
||||
],
|
||||
'Mode of Payment': [
|
||||
dict(fieldname='mode_of_payment_code', label='Code',
|
||||
fieldtype='Select', insert_after='included_in_print_rate', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)))
|
||||
],
|
||||
'Payment Schedule': [
|
||||
dict(fieldname='mode_of_payment_code', label='Code',
|
||||
fieldtype='Select', insert_after='mode_of_payment', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)),
|
||||
fetch_from="mode_of_payment.mode_of_payment_code", read_only=1),
|
||||
dict(fieldname='bank_account', label='Bank Account',
|
||||
fieldtype='Link', insert_after='mode_of_payment_code', print_hide=1,
|
||||
options="Bank Account"),
|
||||
dict(fieldname='bank_account_name', label='Bank Account Name',
|
||||
fieldtype='Data', insert_after='bank_account', print_hide=1,
|
||||
fetch_from="bank_account.account_name", read_only=1),
|
||||
dict(fieldname='bank_account_no', label='Bank Account No',
|
||||
fieldtype='Data', insert_after='bank_account_name', print_hide=1,
|
||||
fetch_from="bank_account.bank_account_no", read_only=1),
|
||||
dict(fieldname='bank_account_iban', label='IBAN',
|
||||
fieldtype='Data', insert_after='bank_account_name', print_hide=1,
|
||||
fetch_from="bank_account.iban", read_only=1),
|
||||
],
|
||||
"Sales Invoice": [
|
||||
dict(fieldname='vat_collectability', label='VAT Collectability',
|
||||
fieldtype='Select', insert_after='taxes_and_charges', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options)),
|
||||
fetch_from="company.vat_collectability"),
|
||||
dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing',
|
||||
fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1),
|
||||
dict(fieldname='company_tax_id', label='Company Tax ID',
|
||||
fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1,
|
||||
fetch_from="company.tax_id"),
|
||||
dict(fieldname='company_fiscal_code', label='Company Fiscal Code',
|
||||
fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1,
|
||||
fetch_from="company.fiscal_code"),
|
||||
dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime',
|
||||
fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1,
|
||||
fetch_from="company.fiscal_regime"),
|
||||
dict(fieldname='cb_e_invoicing_reference', fieldtype='Column Break',
|
||||
insert_after='company_fiscal_regime', print_hide=1),
|
||||
dict(fieldname='customer_fiscal_code', label='Customer Fiscal Code',
|
||||
fieldtype='Data', insert_after='cb_e_invoicing_reference', read_only=1,
|
||||
fetch_from="customer.fiscal_code"),
|
||||
],
|
||||
'Purchase Invoice Item': invoice_item_fields,
|
||||
custom_fields = {
|
||||
'Company': [
|
||||
dict(fieldname='sb_e_invoicing', label='E-Invoicing',
|
||||
fieldtype='Section Break', insert_after='date_of_establishment', print_hide=1),
|
||||
dict(fieldname='fiscal_regime', label='Fiscal Regime',
|
||||
fieldtype='Select', insert_after='sb_e_invoicing', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), fiscal_regimes))),
|
||||
dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='fiscal_regime', print_hide=1,
|
||||
description=_("Applicable if the company is an Individual or a Proprietorship")),
|
||||
dict(fieldname='vat_collectability', label='VAT Collectability',
|
||||
fieldtype='Select', insert_after='fiscal_code', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options))),
|
||||
dict(fieldname='cb_e_invoicing1', fieldtype='Column Break', insert_after='vat_collectability', print_hide=1),
|
||||
dict(fieldname='registrar_office_province', label='Province of the Registrar Office',
|
||||
fieldtype='Data', insert_after='cb_e_invoicing1', print_hide=1, length=2),
|
||||
dict(fieldname='registration_number', label='Registration Number',
|
||||
fieldtype='Data', insert_after='registrar_office_province', print_hide=1, length=20),
|
||||
dict(fieldname='share_capital_amount', label='Share Capital',
|
||||
fieldtype='Currency', insert_after='registration_number', print_hide=1,
|
||||
description=_('Applicable if the company is SpA, SApA or SRL')),
|
||||
dict(fieldname='no_of_members', label='No of Members',
|
||||
fieldtype='Select', insert_after='share_capital_amount', print_hide=1,
|
||||
options="\nSU-Socio Unico\nSM-Piu Soci", description=_("Applicable if the company is a limited liability company")),
|
||||
dict(fieldname='liquidation_state', label='Liquidation State',
|
||||
fieldtype='Select', insert_after='no_of_members', print_hide=1,
|
||||
options="\nLS-In Liquidazione\nLN-Non in Liquidazione")
|
||||
],
|
||||
'Sales Taxes and Charges': [
|
||||
dict(fieldname='tax_exemption_reason', label='Tax Exemption Reason',
|
||||
fieldtype='Select', insert_after='included_in_print_rate', print_hide=1,
|
||||
depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0',
|
||||
options="\n" + "\n".join(map(lambda x: x.decode('utf-8'), tax_exemption_reasons))),
|
||||
dict(fieldname='tax_exemption_law', label='Tax Exempt Under',
|
||||
fieldtype='Text', insert_after='tax_exemption_reason', print_hide=1,
|
||||
depends_on='eval:doc.charge_type!="Actual" && doc.rate==0.0')
|
||||
],
|
||||
'Customer': [
|
||||
dict(fieldname='fiscal_code', label='Fiscal Code', fieldtype='Data', insert_after='tax_id', print_hide=1),
|
||||
dict(fieldname='recipient_code', label='Recipient Code',
|
||||
fieldtype='Data', insert_after='fiscal_code', print_hide=1, default="0000000"),
|
||||
dict(fieldname='pec', label='Recipient PEC',
|
||||
fieldtype='Data', insert_after='fiscal_code', print_hide=1),
|
||||
dict(fieldname='is_public_administration', label='Is Public Administration',
|
||||
fieldtype='Check', insert_after='is_internal_customer', print_hide=1,
|
||||
description=_("Set this if the customer is a Public Administration company."),
|
||||
depends_on='eval:doc.customer_type=="Company"'),
|
||||
dict(fieldname='first_name', label='First Name', fieldtype='Data',
|
||||
insert_after='salutation', print_hide=1, depends_on='eval:doc.customer_type!="Company"'),
|
||||
dict(fieldname='last_name', label='Last Name', fieldtype='Data',
|
||||
insert_after='first_name', print_hide=1, depends_on='eval:doc.customer_type!="Company"')
|
||||
],
|
||||
'Mode of Payment': [
|
||||
dict(fieldname='mode_of_payment_code', label='Code',
|
||||
fieldtype='Select', insert_after='included_in_print_rate', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)))
|
||||
],
|
||||
'Payment Schedule': [
|
||||
dict(fieldname='mode_of_payment_code', label='Code',
|
||||
fieldtype='Select', insert_after='mode_of_payment', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), mode_of_payment_codes)),
|
||||
fetch_from="mode_of_payment.mode_of_payment_code", read_only=1),
|
||||
dict(fieldname='bank_account', label='Bank Account',
|
||||
fieldtype='Link', insert_after='mode_of_payment_code', print_hide=1,
|
||||
options="Bank Account"),
|
||||
dict(fieldname='bank_account_name', label='Bank Account Name',
|
||||
fieldtype='Data', insert_after='bank_account', print_hide=1,
|
||||
fetch_from="bank_account.account_name", read_only=1),
|
||||
dict(fieldname='bank_account_no', label='Bank Account No',
|
||||
fieldtype='Data', insert_after='bank_account_name', print_hide=1,
|
||||
fetch_from="bank_account.bank_account_no", read_only=1),
|
||||
dict(fieldname='bank_account_iban', label='IBAN',
|
||||
fieldtype='Data', insert_after='bank_account_name', print_hide=1,
|
||||
fetch_from="bank_account.iban", read_only=1),
|
||||
],
|
||||
"Sales Invoice": [
|
||||
dict(fieldname='vat_collectability', label='VAT Collectability',
|
||||
fieldtype='Select', insert_after='taxes_and_charges', print_hide=1,
|
||||
options="\n".join(map(lambda x: x.decode('utf-8'), vat_collectability_options)),
|
||||
fetch_from="company.vat_collectability"),
|
||||
dict(fieldname='sb_e_invoicing_reference', label='E-Invoicing',
|
||||
fieldtype='Section Break', insert_after='pos_total_qty', print_hide=1),
|
||||
dict(fieldname='company_tax_id', label='Company Tax ID',
|
||||
fieldtype='Data', insert_after='sb_e_invoicing_reference', print_hide=1, read_only=1,
|
||||
fetch_from="company.tax_id"),
|
||||
dict(fieldname='company_fiscal_code', label='Company Fiscal Code',
|
||||
fieldtype='Data', insert_after='company_tax_id', print_hide=1, read_only=1,
|
||||
fetch_from="company.fiscal_code"),
|
||||
dict(fieldname='company_fiscal_regime', label='Company Fiscal Regime',
|
||||
fieldtype='Data', insert_after='company_fiscal_code', print_hide=1, read_only=1,
|
||||
fetch_from="company.fiscal_regime"),
|
||||
dict(fieldname='cb_e_invoicing_reference', fieldtype='Column Break',
|
||||
insert_after='company_fiscal_regime', print_hide=1),
|
||||
dict(fieldname='customer_fiscal_code', label='Customer Fiscal Code',
|
||||
fieldtype='Data', insert_after='cb_e_invoicing_reference', read_only=1,
|
||||
fetch_from="customer.fiscal_code"),
|
||||
],
|
||||
'Purchase Invoice Item': invoice_item_fields,
|
||||
'Sales Order Item': invoice_item_fields,
|
||||
'Delivery Note Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields,
|
||||
'Sales Invoice Item': invoice_item_fields,
|
||||
'Quotation Item': invoice_item_fields,
|
||||
'Purchase Order Item': invoice_item_fields,
|
||||
'Purchase Receipt Item': invoice_item_fields,
|
||||
'Supplier Quotation Item': invoice_item_fields,
|
||||
'Address': [
|
||||
dict(fieldname='country_code', label='Country Code',
|
||||
fieldtype='Data', insert_after='country', print_hide=1, read_only=1,
|
||||
fetch_from="country.code"),
|
||||
dict(fieldname='state_code', label='State Code',
|
||||
fieldtype='Data', insert_after='state', print_hide=1)
|
||||
]
|
||||
}
|
||||
'Address': [
|
||||
dict(fieldname='country_code', label='Country Code',
|
||||
fieldtype='Data', insert_after='country', print_hide=1, read_only=1,
|
||||
fetch_from="country.code"),
|
||||
dict(fieldname='state_code', label='State Code',
|
||||
fieldtype='Data', insert_after='state', print_hide=1)
|
||||
]
|
||||
}
|
||||
|
||||
create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update)
|
||||
create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch, update=update)
|
||||
|
||||
def setup_report():
|
||||
report_name = 'Electronic Invoice Register'
|
||||
report_name = 'Electronic Invoice Register'
|
||||
|
||||
frappe.db.sql(""" update `tabReport` set disabled = 0 where
|
||||
name = %s """, report_name)
|
||||
frappe.db.sql(""" update `tabReport` set disabled = 0 where
|
||||
name = %s """, report_name)
|
||||
|
||||
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
|
||||
frappe.get_doc(dict(
|
||||
doctype='Custom Role',
|
||||
report=report_name,
|
||||
roles= [
|
||||
dict(role='Accounts User'),
|
||||
dict(role='Accounts Manager')
|
||||
]
|
||||
)).insert()
|
||||
if not frappe.db.get_value('Custom Role', dict(report=report_name)):
|
||||
frappe.get_doc(dict(
|
||||
doctype='Custom Role',
|
||||
report=report_name,
|
||||
roles= [
|
||||
dict(role='Accounts User'),
|
||||
dict(role='Accounts Manager')
|
||||
]
|
||||
)).insert()
|
||||
|
@ -183,6 +183,9 @@ def get_invoice_summary(items, taxes):
|
||||
#Preflight for successful e-invoice export.
|
||||
def sales_invoice_validate(doc):
|
||||
#Validate company
|
||||
if doc.doctype != 'Sales Invoice':
|
||||
return
|
||||
|
||||
if not doc.company_address:
|
||||
frappe.throw(_("Please set an Address on the Company '%s'" % doc.company), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
@ -219,8 +222,12 @@ def sales_invoice_validate(doc):
|
||||
|
||||
|
||||
#Ensure payment details are valid for e-invoice.
|
||||
def sales_invoice_on_submit(doc):
|
||||
def sales_invoice_on_submit(doc, method):
|
||||
#Validate payment details
|
||||
if get_company_country(doc.company) not in ['Italy',
|
||||
'Italia', 'Italian Republic', 'Repubblica Italiana']:
|
||||
return
|
||||
|
||||
if not len(doc.payment_schedule):
|
||||
frappe.throw(_("Please set the Payment Schedule"), title=_("E-Invoicing Information Missing"))
|
||||
else:
|
||||
@ -244,10 +251,17 @@ def prepare_and_attach_invoice(doc):
|
||||
save_file(xml_filename, invoice_xml, dt=doc.doctype, dn=doc.name, is_private=True)
|
||||
|
||||
#Delete e-invoice attachment on cancel.
|
||||
def sales_invoice_on_cancel(doc):
|
||||
def sales_invoice_on_cancel(doc, method):
|
||||
if get_company_country(doc.company) not in ['Italy',
|
||||
'Italia', 'Italian Republic', 'Repubblica Italiana']:
|
||||
return
|
||||
|
||||
for attachment in get_e_invoice_attachments(doc):
|
||||
remove_file(attachment.name, attached_to_doctype=doc.doctype, attached_to_name=doc.name)
|
||||
|
||||
def get_company_country(company):
|
||||
return frappe.get_cached_value('Company', company, 'country')
|
||||
|
||||
def get_e_invoice_attachments(invoice):
|
||||
out = []
|
||||
attachments = get_attachments(invoice.doctype, invoice.name)
|
||||
@ -285,7 +299,10 @@ def get_progressive_name_and_number(doc):
|
||||
|
||||
return progressive_name, progressive_number
|
||||
|
||||
def validate_address(doc, method):
|
||||
def set_state_code(doc, method):
|
||||
if not doc.get('state'):
|
||||
return
|
||||
|
||||
if not (hasattr(doc, "state_code") and doc.country in ["Italy", "Italia", "Italian Republic", "Repubblica Italiana"]):
|
||||
return
|
||||
|
||||
|
@ -16,8 +16,9 @@ def get_setup_progress():
|
||||
return frappe.local.setup_progress
|
||||
|
||||
def get_action_completed_state(action_name):
|
||||
return [d.is_completed for d in get_setup_progress().actions
|
||||
if d.action_name == action_name][0]
|
||||
for d in get_setup_progress().actions:
|
||||
if d.action_name == action_name:
|
||||
return d.is_completed
|
||||
|
||||
def update_action_completed_state(action_name):
|
||||
action_table_doc = [d for d in get_setup_progress().actions
|
||||
|
@ -28,7 +28,7 @@ def get_data(item_code=None, warehouse=None, item_group=None,
|
||||
# user does not have access on warehouse
|
||||
return []
|
||||
|
||||
return frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty',
|
||||
items = frappe.db.get_all('Bin', fields=['item_code', 'warehouse', 'projected_qty',
|
||||
'reserved_qty', 'reserved_qty_for_production', 'reserved_qty_for_sub_contract', 'actual_qty', 'valuation_rate'],
|
||||
or_filters={
|
||||
'projected_qty': ['!=', 0],
|
||||
@ -41,3 +41,10 @@ def get_data(item_code=None, warehouse=None, item_group=None,
|
||||
order_by=sort_by + ' ' + sort_order,
|
||||
limit_start=start,
|
||||
limit_page_length='21')
|
||||
|
||||
for item in items:
|
||||
item.update({
|
||||
'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name')
|
||||
})
|
||||
|
||||
return items
|
||||
|
@ -391,7 +391,7 @@ def get_invoiced_qty_map(delivery_note):
|
||||
|
||||
return invoiced_qty_map
|
||||
|
||||
def get_returned_qty_map(sales_orders):
|
||||
def get_returned_qty_map_against_so(sales_orders):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = {}
|
||||
|
||||
@ -403,12 +403,25 @@ def get_returned_qty_map(sales_orders):
|
||||
|
||||
return returned_qty_map
|
||||
|
||||
def get_returned_qty_map_against_dn(delivery_note):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select dn_item.item_code, sum(abs(dn_item.qty)) as qty
|
||||
from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn
|
||||
where dn.name = dn_item.parent
|
||||
and dn.docstatus = 1
|
||||
and dn.is_return = 1
|
||||
and dn.return_against = %s
|
||||
group by dn_item.item_code
|
||||
""", delivery_note))
|
||||
|
||||
return returned_qty_map
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_invoice(source_name, target_doc=None):
|
||||
doc = frappe.get_doc('Delivery Note', source_name)
|
||||
sales_orders = [d.against_sales_order for d in doc.items]
|
||||
returned_qty_map = get_returned_qty_map(sales_orders)
|
||||
|
||||
returned_qty_map_against_so = get_returned_qty_map_against_so(sales_orders)
|
||||
returned_qty_map_against_dn = get_returned_qty_map_against_dn(source_name)
|
||||
invoiced_qty_map = get_invoiced_qty_map(source_name)
|
||||
|
||||
def set_missing_values(source, target):
|
||||
@ -428,13 +441,26 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
|
||||
|
||||
def update_item(source_doc, target_doc, source_parent):
|
||||
target_doc.qty = (source_doc.qty -
|
||||
invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0))
|
||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
||||
if not source_doc.so_detail:
|
||||
returned_qty_map_against_dn[source_doc.item_code] = returned_qty
|
||||
|
||||
if source_doc.serial_no and source_parent.per_billed > 0:
|
||||
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
|
||||
target_doc.qty, source_parent.name)
|
||||
|
||||
def get_pending_qty(item_row):
|
||||
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) - returned_qty_map_against_so.get(item_row.so_detail, 0)
|
||||
returned_qty = flt(returned_qty_map_against_dn.get(item_row.item_code, 0))
|
||||
if not item_row.so_detail:
|
||||
if returned_qty >= pending_qty:
|
||||
pending_qty = 0
|
||||
returned_qty -= pending_qty
|
||||
else:
|
||||
pending_qty -= returned_qty
|
||||
returned_qty = 0
|
||||
return pending_qty, returned_qty
|
||||
|
||||
doc = get_mapped_doc("Delivery Note", source_name, {
|
||||
"Delivery Note": {
|
||||
"doctype": "Sales Invoice",
|
||||
@ -453,7 +479,7 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
"cost_center": "cost_center"
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0
|
||||
"filter": lambda d: get_pending_qty(d)[0]<=0
|
||||
},
|
||||
"Sales Taxes and Charges": {
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
|
@ -636,7 +636,7 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
|
||||
|
||||
set_perpetual_inventory(0, company)
|
||||
|
||||
|
||||
def test_make_sales_invoice_from_dn_for_returned_qty(self):
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
||||
@ -655,6 +655,33 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
si = make_sales_invoice(dn.name)
|
||||
self.assertEquals(si.items[0].qty, 1)
|
||||
|
||||
def test_make_sales_invoice_from_dn_with_returned_qty_against_dn(self):
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
||||
|
||||
dn = create_delivery_note(qty=8, do_not_submit=True)
|
||||
dn.append("items", {
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"rate": 100,
|
||||
"conversion_factor": 1.0,
|
||||
"expense_account": "Cost of Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
dn.submit()
|
||||
|
||||
si1 = make_sales_invoice(dn.name)
|
||||
si1.items[0].qty = 4
|
||||
si1.items.pop(1)
|
||||
si1.save()
|
||||
si1.submit()
|
||||
|
||||
create_delivery_note(is_return=1, return_against=dn.name, qty=-2)
|
||||
|
||||
si2 = make_sales_invoice(dn.name)
|
||||
self.assertEquals(si2.items[0].qty, 2)
|
||||
self.assertEquals(si2.items[1].qty, 1)
|
||||
|
||||
def create_delivery_note(**args):
|
||||
dn = frappe.new_doc("Delivery Note")
|
||||
args = frappe._dict(args)
|
||||
|
@ -85,7 +85,7 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
// stop
|
||||
frm.add_custom_button(__('Stop'),
|
||||
() => frm.events.update_status(frm, 'Stop'));
|
||||
() => frm.events.update_status(frm, 'Stopped'));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ class PurchaseReceipt(BuyingController):
|
||||
else:
|
||||
self.status = "Completed"
|
||||
|
||||
|
||||
|
||||
# Updating stock ledger should always be called after updating prevdoc status,
|
||||
# because updating ordered qty, reserved_qty_for_subcontract in bin
|
||||
# depends upon updated ordered qty in PO
|
||||
@ -311,7 +311,7 @@ class PurchaseReceipt(BuyingController):
|
||||
"\n".join(warehouse_with_no_account))
|
||||
|
||||
return process_gl_map(gl_entries)
|
||||
|
||||
|
||||
def get_asset_gl_entry(self, gl_entries):
|
||||
for d in self.get("items"):
|
||||
if d.is_fixed_asset:
|
||||
@ -405,6 +405,11 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
|
||||
@frappe.whitelist()
|
||||
def make_purchase_invoice(source_name, target_doc=None):
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
doc = frappe.get_doc('Purchase Receipt', source_name)
|
||||
purchase_orders = [d.purchase_order for d in doc.items]
|
||||
returned_qty_map_against_po = get_returned_qty_map_against_po(purchase_orders)
|
||||
returned_qty_map_against_pr = get_returned_qty_map_against_pr(source_name)
|
||||
|
||||
invoiced_qty_map = get_invoiced_qty_map(source_name)
|
||||
|
||||
def set_missing_values(source, target):
|
||||
@ -417,7 +422,23 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(source_doc, target_doc, source_parent):
|
||||
target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
|
||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
||||
if not source_doc.purchase_order_item:
|
||||
returned_qty_map_against_pr[source_doc.item_code] = returned_qty
|
||||
|
||||
def get_pending_qty(item_row):
|
||||
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0) \
|
||||
- returned_qty_map_against_po.get(item_row.purchase_order_item, 0)
|
||||
returned_qty = flt(returned_qty_map_against_pr.get(item_row.item_code, 0))
|
||||
if not item_row.purchase_order_item:
|
||||
if returned_qty >= pending_qty:
|
||||
pending_qty = 0
|
||||
returned_qty -= pending_qty
|
||||
else:
|
||||
pending_qty -= returned_qty
|
||||
returned_qty = 0
|
||||
return pending_qty, returned_qty
|
||||
|
||||
|
||||
doclist = get_mapped_doc("Purchase Receipt", source_name, {
|
||||
"Purchase Receipt": {
|
||||
@ -440,7 +461,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
"asset": "asset",
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"filter": lambda d: abs(d.qty) - abs(invoiced_qty_map.get(d.name, 0))<=0
|
||||
"filter": lambda d: get_pending_qty(d)[0]<=0
|
||||
},
|
||||
"Purchase Taxes and Charges": {
|
||||
"doctype": "Purchase Taxes and Charges",
|
||||
@ -462,6 +483,31 @@ def get_invoiced_qty_map(purchase_receipt):
|
||||
|
||||
return invoiced_qty_map
|
||||
|
||||
def get_returned_qty_map_against_po(purchase_orders):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = {}
|
||||
|
||||
for name, returned_qty in frappe.get_all('Purchase Order Item', fields = ["name", "returned_qty"],
|
||||
filters = {'parent': ('in', purchase_orders), 'docstatus': 1}, as_list=1):
|
||||
if not returned_qty_map.get(name):
|
||||
returned_qty_map[name] = 0
|
||||
returned_qty_map[name] += returned_qty
|
||||
|
||||
return returned_qty_map
|
||||
|
||||
def get_returned_qty_map_against_pr(purchase_receipt):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select pr_item.item_code, sum(abs(pr_item.qty)) as qty
|
||||
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
|
||||
where pr.name = pr_item.parent
|
||||
and pr.docstatus = 1
|
||||
and pr.is_return = 1
|
||||
and pr.return_against = %s
|
||||
group by pr_item.item_code
|
||||
""", purchase_receipt))
|
||||
|
||||
return returned_qty_map
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_return(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
|
@ -404,6 +404,44 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
|
||||
set_perpetual_inventory(0, pr.company)
|
||||
|
||||
def test_make_purchase_invoice_from_pr_for_returned_qty(self):
|
||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, create_pr_against_po
|
||||
|
||||
po = create_purchase_order()
|
||||
pr = create_pr_against_po(po.name)
|
||||
|
||||
pr1 = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-1, do_not_submit=True)
|
||||
pr1.items[0].purchase_order = po.name
|
||||
pr1.items[0].purchase_order_item = po.items[0].name
|
||||
pr1.submit()
|
||||
|
||||
pi = make_purchase_invoice(pr.name)
|
||||
self.assertEquals(pi.items[0].qty, 3)
|
||||
|
||||
def test_make_purchase_invoice_from_dn_with_returned_qty_against_dn(self):
|
||||
pr1 = make_purchase_receipt(qty=8, do_not_submit=True)
|
||||
pr1.append("items", {
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 1,
|
||||
"received_qty": 1,
|
||||
"rate": 100,
|
||||
"conversion_factor": 1.0,
|
||||
})
|
||||
pr1.submit()
|
||||
|
||||
pi1 = make_purchase_invoice(pr1.name)
|
||||
pi1.items[0].qty = 4
|
||||
pi1.items.pop(1)
|
||||
pi1.save()
|
||||
pi1.submit()
|
||||
|
||||
make_purchase_receipt(is_return=1, return_against=pr1.name, qty=-2)
|
||||
|
||||
pi2 = make_purchase_invoice(pr1.name)
|
||||
self.assertEquals(pi2.items[0].qty, 2)
|
||||
self.assertEquals(pi2.items[1].qty, 1)
|
||||
|
||||
def get_gl_entries(voucher_type, voucher_no):
|
||||
return frappe.db.sql("""select account, debit, credit, cost_center
|
||||
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
|
||||
|
Loading…
x
Reference in New Issue
Block a user