mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-05 22:48:27 +00:00
Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into gst_taxtable_value_with_discount
This commit is contained in:
6
.github/workflows/patch.yml
vendored
6
.github/workflows/patch.yml
vendored
@@ -66,4 +66,8 @@ jobs:
|
|||||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||||
|
|
||||||
- name: Run Patch Tests
|
- name: Run Patch Tests
|
||||||
run: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
|
run: |
|
||||||
|
cd ~/frappe-bench/
|
||||||
|
wget https://erpnext.com/files/v10-erpnext.sql.gz
|
||||||
|
bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz
|
||||||
|
bench --site test_site migrate
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2020-09-12 22:26:19.594367",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"document_type": "Setup",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"add_deduct_tax",
|
||||||
|
"charge_type",
|
||||||
|
"row_id",
|
||||||
|
"account_head",
|
||||||
|
"col_break_1",
|
||||||
|
"description",
|
||||||
|
"included_in_paid_amount",
|
||||||
|
"accounting_dimensions_section",
|
||||||
|
"cost_center",
|
||||||
|
"dimension_col_break",
|
||||||
|
"section_break_8",
|
||||||
|
"rate",
|
||||||
|
"section_break_9",
|
||||||
|
"currency",
|
||||||
|
"tax_amount",
|
||||||
|
"total",
|
||||||
|
"allocated_amount",
|
||||||
|
"column_break_13",
|
||||||
|
"base_tax_amount",
|
||||||
|
"base_total",
|
||||||
|
"base_allocated_amount"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "charge_type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Type",
|
||||||
|
"oldfieldname": "charge_type",
|
||||||
|
"oldfieldtype": "Select",
|
||||||
|
"options": "\nActual\nOn Paid Amount\nOn Previous Row Amount\nOn Previous Row Total",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:[\"On Previous Row Amount\", \"On Previous Row Total\"].indexOf(doc.charge_type)!==-1",
|
||||||
|
"fieldname": "row_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Reference Row #",
|
||||||
|
"oldfieldname": "row_id",
|
||||||
|
"oldfieldtype": "Data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "account_head",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Account Head",
|
||||||
|
"oldfieldname": "account_head",
|
||||||
|
"oldfieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"reqd": 1,
|
||||||
|
"search_index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "col_break_1",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"width": "50%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Description",
|
||||||
|
"oldfieldname": "description",
|
||||||
|
"oldfieldtype": "Small Text",
|
||||||
|
"print_width": "300px",
|
||||||
|
"reqd": 1,
|
||||||
|
"width": "300px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "accounting_dimensions_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Accounting Dimensions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": ":Company",
|
||||||
|
"fieldname": "cost_center",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Cost Center",
|
||||||
|
"oldfieldname": "cost_center_other_charges",
|
||||||
|
"oldfieldtype": "Link",
|
||||||
|
"options": "Cost Center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "dimension_col_break",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_8",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "rate",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Rate",
|
||||||
|
"oldfieldname": "rate",
|
||||||
|
"oldfieldtype": "Currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_9",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "tax_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Amount",
|
||||||
|
"options": "currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Total",
|
||||||
|
"options": "currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_13",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_tax_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Amount (Company Currency)",
|
||||||
|
"oldfieldname": "tax_amount",
|
||||||
|
"oldfieldtype": "Currency",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Total (Company Currency)",
|
||||||
|
"oldfieldname": "total",
|
||||||
|
"oldfieldtype": "Currency",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "add_deduct_tax",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Add Or Deduct",
|
||||||
|
"options": "Add\nDeduct",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "included_in_paid_amount",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Considered In Paid Amount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "allocated_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Allocated Amount",
|
||||||
|
"options": "currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_allocated_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Allocated Amount (Company Currency)",
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "account_head.account_currency",
|
||||||
|
"fieldname": "currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Account Currency",
|
||||||
|
"options": "Currency",
|
||||||
|
"read_only": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-06-09 11:46:58.373170",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Advance Taxes and Charges",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "ASC"
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class AdvanceTaxesandCharges(Document):
|
||||||
|
pass
|
||||||
@@ -54,7 +54,7 @@ class CForm(Document):
|
|||||||
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
||||||
|
|
||||||
def set_total_invoiced_amount(self):
|
def set_total_invoiced_amount(self):
|
||||||
total = sum([flt(d.grand_total) for d in self.get('invoices')])
|
total = sum(flt(d.grand_total) for d in self.get('invoices'))
|
||||||
frappe.db.set(self, 'total_invoiced_amount', total)
|
frappe.db.set(self, 'total_invoiced_amount', total)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class CouponCode(Document):
|
|||||||
|
|
||||||
if not self.coupon_code:
|
if not self.coupon_code:
|
||||||
if self.coupon_type == "Promotional":
|
if self.coupon_type == "Promotional":
|
||||||
self.coupon_code =''.join([i for i in self.coupon_name if not i.isdigit()])[0:8].upper()
|
self.coupon_code =''.join(i for i in self.coupon_name if not i.isdigit())[0:8].upper()
|
||||||
elif self.coupon_type == "Gift Card":
|
elif self.coupon_type == "Gift Card":
|
||||||
self.coupon_code = frappe.generate_hash()[:10].upper()
|
self.coupon_code = frappe.generate_hash()[:10].upper()
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class InvoiceDiscounting(AccountsController):
|
|||||||
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)))
|
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)))
|
||||||
|
|
||||||
def calculate_total_amount(self):
|
def calculate_total_amount(self):
|
||||||
self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
|
self.total_amount = sum(flt(d.outstanding_amount) for d in self.invoices)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.update_sales_invoice()
|
self.update_sales_invoice()
|
||||||
|
|||||||
@@ -196,8 +196,8 @@ class JournalEntry(AccountsController):
|
|||||||
frappe.throw(_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
|
frappe.throw(_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
|
||||||
|
|
||||||
def check_credit_limit(self):
|
def check_credit_limit(self):
|
||||||
customers = list(set([d.party for d in self.get("accounts")
|
customers = list(set(d.party for d in self.get("accounts")
|
||||||
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
|
if d.party_type=="Customer" and d.party and flt(d.debit) > 0))
|
||||||
if customers:
|
if customers:
|
||||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||||
for customer in customers:
|
for customer in customers:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class MonthlyDistribution(Document):
|
|||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
total = sum([flt(d.percentage_allocation) for d in self.get("percentages")])
|
total = sum(flt(d.percentage_allocation) for d in self.get("percentages"))
|
||||||
|
|
||||||
if flt(total, 2) != 100.0:
|
if flt(total, 2) != 100.0:
|
||||||
frappe.throw(_("Percentage Allocation should be equal to 100%") + \
|
frappe.throw(_("Percentage Allocation should be equal to 100%") + \
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
{% include "erpnext/public/js/controllers/accounts.js" %}
|
{% include "erpnext/public/js/controllers/accounts.js" %}
|
||||||
frappe.provide("erpnext.accounts.dimensions");
|
frappe.provide("erpnext.accounts.dimensions");
|
||||||
|
|
||||||
|
cur_frm.cscript.tax_table = "Advance Taxes and Charges";
|
||||||
|
|
||||||
frappe.ui.form.on('Payment Entry', {
|
frappe.ui.form.on('Payment Entry', {
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if(frm.doc.__islocal) {
|
if(frm.doc.__islocal) {
|
||||||
@@ -91,6 +93,16 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.set_query("advance_tax_account", function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
"company": frm.doc.company,
|
||||||
|
"root_type": ["in", ["Asset", "Liability"]],
|
||||||
|
"is_group": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
frm.set_query("reference_doctype", "references", function() {
|
frm.set_query("reference_doctype", "references", function() {
|
||||||
if (frm.doc.party_type == "Customer") {
|
if (frm.doc.party_type == "Customer") {
|
||||||
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
|
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
|
||||||
@@ -182,6 +194,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
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.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
|
frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
|
||||||
|
frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
|
||||||
|
(frm.doc.paid_from_account_currency != company_currency));
|
||||||
|
|
||||||
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
|
||||||
@@ -216,7 +230,7 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: "";
|
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: "";
|
||||||
|
|
||||||
frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
|
frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
|
||||||
"difference_amount"], company_currency);
|
"difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency);
|
||||||
|
|
||||||
frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency);
|
frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency);
|
||||||
frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency);
|
frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency);
|
||||||
@@ -224,11 +238,13 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
var party_account_currency = frm.doc.payment_type=="Receive" ?
|
var party_account_currency = frm.doc.payment_type=="Receive" ?
|
||||||
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.set_currency_labels(["total_allocated_amount", "unallocated_amount"], party_account_currency);
|
frm.set_currency_labels(["total_allocated_amount", "unallocated_amount",
|
||||||
|
"total_taxes_and_charges"], party_account_currency);
|
||||||
|
|
||||||
var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency"
|
var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency"
|
||||||
frm.set_df_property("total_allocated_amount", "options", currency_field);
|
frm.set_df_property("total_allocated_amount", "options", currency_field);
|
||||||
frm.set_df_property("unallocated_amount", "options", currency_field);
|
frm.set_df_property("unallocated_amount", "options", currency_field);
|
||||||
|
frm.set_df_property("total_taxes_and_charges", "options", currency_field);
|
||||||
frm.set_df_property("party_balance", "options", currency_field);
|
frm.set_df_property("party_balance", "options", currency_field);
|
||||||
|
|
||||||
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
|
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
|
||||||
@@ -364,6 +380,16 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
apply_tax_withholding_amount: function(frm) {
|
||||||
|
if (!frm.doc.apply_tax_withholding_amount) {
|
||||||
|
frm.set_value("tax_withholding_category", '');
|
||||||
|
} else {
|
||||||
|
frappe.db.get_value('Supplier', frm.doc.party, 'tax_withholding_category', (values) => {
|
||||||
|
frm.set_value("tax_withholding_category", values.tax_withholding_category);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
paid_from: function(frm) {
|
paid_from: function(frm) {
|
||||||
if(frm.set_party_account_based_on_party) return;
|
if(frm.set_party_account_based_on_party) return;
|
||||||
|
|
||||||
@@ -843,12 +869,12 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
if(frm.doc.payment_type == "Receive"
|
if(frm.doc.payment_type == "Receive"
|
||||||
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
|
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
|
||||||
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
|
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
|
||||||
unallocated_amount = (frm.doc.base_received_amount + total_deductions
|
unallocated_amount = (frm.doc.base_received_amount + total_deductions + frm.doc.base_total_taxes_and_charges
|
||||||
- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
|
+ frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
|
||||||
} else if (frm.doc.payment_type == "Pay"
|
} else if (frm.doc.payment_type == "Pay"
|
||||||
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions
|
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions
|
||||||
&& frm.doc.total_allocated_amount < frm.doc.received_amount + (total_deductions / frm.doc.target_exchange_rate)) {
|
&& frm.doc.total_allocated_amount < frm.doc.received_amount + (total_deductions / frm.doc.target_exchange_rate)) {
|
||||||
unallocated_amount = (frm.doc.base_paid_amount - (total_deductions
|
unallocated_amount = (frm.doc.base_paid_amount + frm.doc.base_total_taxes_and_charges - (total_deductions
|
||||||
+ frm.doc.base_total_allocated_amount)) / frm.doc.target_exchange_rate;
|
+ frm.doc.base_total_allocated_amount)) / frm.doc.target_exchange_rate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -874,7 +900,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
|
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
|
||||||
function(d) { return flt(d.amount) }));
|
function(d) { return flt(d.amount) }));
|
||||||
|
|
||||||
frm.set_value("difference_amount", difference_amount - total_deductions);
|
frm.set_value("difference_amount", difference_amount - total_deductions +
|
||||||
|
frm.doc.base_total_taxes_and_charges);
|
||||||
|
|
||||||
frm.events.hide_unhide_fields(frm);
|
frm.events.hide_unhide_fields(frm);
|
||||||
},
|
},
|
||||||
@@ -1002,7 +1029,203 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
sales_taxes_and_charges_template: function(frm) {
|
||||||
|
frm.trigger('fetch_taxes_from_template');
|
||||||
|
},
|
||||||
|
|
||||||
|
purchase_taxes_and_charges_template: function(frm) {
|
||||||
|
frm.trigger('fetch_taxes_from_template');
|
||||||
|
},
|
||||||
|
|
||||||
|
fetch_taxes_from_template: function(frm) {
|
||||||
|
let master_doctype = '';
|
||||||
|
let taxes_and_charges = '';
|
||||||
|
|
||||||
|
if (frm.doc.party_type == 'Supplier') {
|
||||||
|
master_doctype = 'Purchase Taxes and Charges Template';
|
||||||
|
taxes_and_charges = frm.doc.purchase_taxes_and_charges_template;
|
||||||
|
} else if (frm.doc.party_type == 'Customer') {
|
||||||
|
master_doctype = 'Sales Taxes and Charges Template';
|
||||||
|
taxes_and_charges = frm.doc.sales_taxes_and_charges_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!taxes_and_charges) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.controllers.accounts_controller.get_taxes_and_charges",
|
||||||
|
args: {
|
||||||
|
"master_doctype": master_doctype,
|
||||||
|
"master_name": taxes_and_charges
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if(!r.exc && r.message) {
|
||||||
|
// set taxes table
|
||||||
|
if(r.message) {
|
||||||
|
for (let tax of r.message) {
|
||||||
|
if (tax.charge_type === 'On Net Total') {
|
||||||
|
tax.charge_type = 'On Paid Amount';
|
||||||
|
}
|
||||||
|
me.frm.add_child("taxes", tax);
|
||||||
|
}
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
apply_taxes: function(frm) {
|
||||||
|
frm.events.initialize_taxes(frm);
|
||||||
|
frm.events.determine_exclusive_rate(frm);
|
||||||
|
frm.events.calculate_taxes(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize_taxes: function(frm) {
|
||||||
|
$.each(frm.doc["taxes"] || [], function(i, tax) {
|
||||||
|
tax.item_wise_tax_detail = {};
|
||||||
|
let tax_fields = ["total", "tax_fraction_for_current_item",
|
||||||
|
"grand_total_fraction_for_current_item"];
|
||||||
|
|
||||||
|
if (cstr(tax.charge_type) != "Actual") {
|
||||||
|
tax_fields.push("tax_amount");
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0; });
|
||||||
|
|
||||||
|
frm.doc.paid_amount_after_tax = frm.doc.paid_amount;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
determine_exclusive_rate: function(frm) {
|
||||||
|
let has_inclusive_tax = false;
|
||||||
|
$.each(frm.doc["taxes"] || [], function(i, row) {
|
||||||
|
if(cint(row.included_in_paid_amount)) has_inclusive_tax = true;
|
||||||
|
});
|
||||||
|
if(has_inclusive_tax==false) return;
|
||||||
|
|
||||||
|
let cumulated_tax_fraction = 0.0;
|
||||||
|
$.each(frm.doc["taxes"] || [], function(i, tax) {
|
||||||
|
let current_tax_fraction = frm.events.get_current_tax_fraction(frm, tax);
|
||||||
|
tax.tax_fraction_for_current_item = current_tax_fraction[0];
|
||||||
|
|
||||||
|
if(i==0) {
|
||||||
|
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
|
||||||
|
} else {
|
||||||
|
tax.grand_total_fraction_for_current_item =
|
||||||
|
me.frm.doc["taxes"][i-1].grand_total_fraction_for_current_item +
|
||||||
|
tax.tax_fraction_for_current_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulated_tax_fraction += tax.tax_fraction_for_current_item;
|
||||||
|
frm.doc.paid_amount_after_tax = flt(frm.doc.paid_amount/(1+cumulated_tax_fraction))
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_current_tax_fraction: function(frm, tax) {
|
||||||
|
let current_tax_fraction = 0.0;
|
||||||
|
|
||||||
|
if(cint(tax.included_in_paid_amount)) {
|
||||||
|
let tax_rate = tax.rate;
|
||||||
|
|
||||||
|
if (tax.charge_type == "Actual") {
|
||||||
|
current_tax_fraction = tax.tax_amount/(frm.doc.paid_amount_after_tax + frm.doc.tax_amount);
|
||||||
|
} else if(tax.charge_type == "On Paid Amount") {
|
||||||
|
current_tax_fraction = (tax_rate / 100.0);
|
||||||
|
} else if(tax.charge_type == "On Previous Row Amount") {
|
||||||
|
current_tax_fraction = (tax_rate / 100.0) *
|
||||||
|
frm.doc["taxes"][cint(tax.row_id) - 1].tax_fraction_for_current_item;
|
||||||
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
|
current_tax_fraction = (tax_rate / 100.0) *
|
||||||
|
frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") {
|
||||||
|
current_tax_fraction *= -1;
|
||||||
|
inclusive_tax_amount_per_qty *= -1;
|
||||||
|
}
|
||||||
|
return current_tax_fraction;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
calculate_taxes: function(frm) {
|
||||||
|
frm.doc.total_taxes_and_charges = 0.0;
|
||||||
|
frm.doc.base_total_taxes_and_charges = 0.0;
|
||||||
|
|
||||||
|
let actual_tax_dict = {};
|
||||||
|
|
||||||
|
// maintain actual tax rate based on idx
|
||||||
|
$.each(frm.doc["taxes"] || [], function(i, tax) {
|
||||||
|
if (tax.charge_type == "Actual") {
|
||||||
|
actual_tax_dict[tax.idx] = flt(tax.tax_amount, precision("tax_amount", tax));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$.each(me.frm.doc["taxes"] || [], function(i, tax) {
|
||||||
|
let current_tax_amount = frm.events.get_current_tax_amount(frm, tax);
|
||||||
|
|
||||||
|
// Adjust divisional loss to the last item
|
||||||
|
if (tax.charge_type == "Actual") {
|
||||||
|
actual_tax_dict[tax.idx] -= current_tax_amount;
|
||||||
|
if (i == frm.doc["taxes"].length - 1) {
|
||||||
|
current_tax_amount += actual_tax_dict[tax.idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tax.tax_amount = current_tax_amount;
|
||||||
|
tax.base_tax_amount = tax.tax_amount * frm.doc.source_exchange_rate;
|
||||||
|
current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
||||||
|
|
||||||
|
if(i==0) {
|
||||||
|
tax.total = flt(frm.doc.paid_amount_after_tax + current_tax_amount, precision("total", tax));
|
||||||
|
} else {
|
||||||
|
tax.total = flt(frm.doc["taxes"][i-1].total + current_tax_amount, precision("total", tax));
|
||||||
|
}
|
||||||
|
|
||||||
|
tax.base_total = tax.total * frm.doc.source_exchange_rate;
|
||||||
|
frm.doc.total_taxes_and_charges += current_tax_amount;
|
||||||
|
frm.doc.base_total_taxes_and_charges += current_tax_amount * frm.doc.source_exchange_rate;
|
||||||
|
|
||||||
|
frm.refresh_field('taxes');
|
||||||
|
frm.refresh_field('total_taxes_and_charges');
|
||||||
|
frm.refresh_field('base_total_taxes_and_charges');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_current_tax_amount: function(frm, tax) {
|
||||||
|
let tax_rate = tax.rate;
|
||||||
|
let current_tax_amount = 0.0;
|
||||||
|
|
||||||
|
// To set row_id by default as previous row.
|
||||||
|
if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
|
||||||
|
if (tax.idx === 1) {
|
||||||
|
frappe.throw(
|
||||||
|
__("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"));
|
||||||
|
}
|
||||||
|
if (!tax.row_id) {
|
||||||
|
tax.row_id = tax.idx - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tax.charge_type == "Actual") {
|
||||||
|
current_tax_amount = flt(tax.tax_amount, precision("tax_amount", tax))
|
||||||
|
} else if(tax.charge_type == "On Paid Amount") {
|
||||||
|
current_tax_amount = flt((tax_rate / 100.0) * frm.doc.paid_amount_after_tax);
|
||||||
|
} else if(tax.charge_type == "On Previous Row Amount") {
|
||||||
|
current_tax_amount = flt((tax_rate / 100.0) *
|
||||||
|
frm.doc["taxes"][cint(tax.row_id) - 1].tax_amount);
|
||||||
|
|
||||||
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
|
current_tax_amount = flt((tax_rate / 100.0) *
|
||||||
|
frm.doc["taxes"][cint(tax.row_id) - 1].total);
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_tax_amount;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -1049,6 +1272,33 @@ frappe.ui.form.on('Payment Entry Reference', {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
frappe.ui.form.on('Advance Taxes and Charges', {
|
||||||
|
rate: function(frm) {
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
tax_amount : function(frm) {
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
row_id: function(frm) {
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
taxes_remove: function(frm) {
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
},
|
||||||
|
|
||||||
|
included_in_paid_amount: function(frm) {
|
||||||
|
frm.events.apply_taxes(frm);
|
||||||
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
frappe.ui.form.on('Payment Entry Deduction', {
|
frappe.ui.form.on('Payment Entry Deduction', {
|
||||||
amount: function(frm) {
|
amount: function(frm) {
|
||||||
frm.events.set_unallocated_amount(frm);
|
frm.events.set_unallocated_amount(frm);
|
||||||
|
|||||||
@@ -35,12 +35,16 @@
|
|||||||
"paid_to_account_balance",
|
"paid_to_account_balance",
|
||||||
"payment_amounts_section",
|
"payment_amounts_section",
|
||||||
"paid_amount",
|
"paid_amount",
|
||||||
|
"paid_amount_after_tax",
|
||||||
"source_exchange_rate",
|
"source_exchange_rate",
|
||||||
"base_paid_amount",
|
"base_paid_amount",
|
||||||
|
"base_paid_amount_after_tax",
|
||||||
"column_break_21",
|
"column_break_21",
|
||||||
"received_amount",
|
"received_amount",
|
||||||
|
"received_amount_after_tax",
|
||||||
"target_exchange_rate",
|
"target_exchange_rate",
|
||||||
"base_received_amount",
|
"base_received_amount",
|
||||||
|
"base_received_amount_after_tax",
|
||||||
"section_break_14",
|
"section_break_14",
|
||||||
"get_outstanding_invoice",
|
"get_outstanding_invoice",
|
||||||
"references",
|
"references",
|
||||||
@@ -52,6 +56,17 @@
|
|||||||
"unallocated_amount",
|
"unallocated_amount",
|
||||||
"difference_amount",
|
"difference_amount",
|
||||||
"write_off_difference_amount",
|
"write_off_difference_amount",
|
||||||
|
"taxes_and_charges_section",
|
||||||
|
"purchase_taxes_and_charges_template",
|
||||||
|
"sales_taxes_and_charges_template",
|
||||||
|
"advance_tax_account",
|
||||||
|
"column_break_55",
|
||||||
|
"apply_tax_withholding_amount",
|
||||||
|
"tax_withholding_category",
|
||||||
|
"section_break_56",
|
||||||
|
"taxes",
|
||||||
|
"base_total_taxes_and_charges",
|
||||||
|
"total_taxes_and_charges",
|
||||||
"deductions_or_loss_section",
|
"deductions_or_loss_section",
|
||||||
"deductions",
|
"deductions",
|
||||||
"transaction_references",
|
"transaction_references",
|
||||||
@@ -320,6 +335,7 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "doc.received_amount",
|
||||||
"fieldname": "base_received_amount",
|
"fieldname": "base_received_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Received Amount (Company Currency)",
|
"label": "Received Amount (Company Currency)",
|
||||||
@@ -584,12 +600,114 @@
|
|||||||
"fieldname": "custom_remarks",
|
"fieldname": "custom_remarks",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Custom Remarks"
|
"label": "Custom Remarks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.apply_tax_withholding_amount",
|
||||||
|
"fieldname": "tax_withholding_category",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Tax Withholding Category",
|
||||||
|
"mandatory_depends_on": "eval:doc.apply_tax_withholding_amount",
|
||||||
|
"options": "Tax Withholding Category"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "eval:doc.party_type == 'Supplier'",
|
||||||
|
"fieldname": "apply_tax_withholding_amount",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Apply Tax Withholding Amount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "taxes_and_charges_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Taxes and Charges"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.party_type == 'Supplier'",
|
||||||
|
"fieldname": "purchase_taxes_and_charges_template",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Taxes and Charges Template",
|
||||||
|
"options": "Purchase Taxes and Charges Template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.party_type == 'Customer'",
|
||||||
|
"fieldname": "sales_taxes_and_charges_template",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Taxes and Charges Template",
|
||||||
|
"options": "Sales Taxes and Charges Template"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: doc.party_type == 'Supplier' || doc.party_type == 'Customer'",
|
||||||
|
"fieldname": "taxes",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Advance Taxes and Charges",
|
||||||
|
"options": "Advance Taxes and Charges"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_total_taxes_and_charges",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Total Taxes and Charges (Company Currency)",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_taxes_and_charges",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Total Taxes and Charges",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "paid_amount_after_tax",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Paid Amount After Tax",
|
||||||
|
"options": "paid_from_account_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "base_paid_amount_after_tax",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Paid Amount After Tax (Company Currency)",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_55",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_56",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hide_border": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.apply_tax_withholding_amount",
|
||||||
|
"description": "Provisional tax account for advance tax. Taxes are parked in this account until payments are allocated to invoices",
|
||||||
|
"fieldname": "advance_tax_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Advance Tax Account",
|
||||||
|
"mandatory_depends_on": "eval:doc.apply_tax_withholding_amount",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.received_amount",
|
||||||
|
"fieldname": "received_amount_after_tax",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Received Amount After Tax",
|
||||||
|
"options": "paid_to_account_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "doc.received_amount",
|
||||||
|
"fieldname": "base_received_amount_after_tax",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Received Amount After Tax (Company Currency)",
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-08 13:05:16.958866",
|
"modified": "2021-06-09 11:55:04.215050",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Entry",
|
"name": "Payment Entry",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext, json
|
import frappe, erpnext, json
|
||||||
from frappe import _, scrub, ValidationError
|
from frappe import _, scrub, ValidationError
|
||||||
from frappe.utils import flt, comma_or, nowdate, getdate
|
from frappe.utils import flt, comma_or, nowdate, getdate, cint
|
||||||
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
|
||||||
from erpnext.accounts.party import get_party_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.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
||||||
@@ -15,6 +15,7 @@ from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo
|
|||||||
from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details
|
from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details
|
||||||
from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status
|
from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status
|
||||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
||||||
|
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
||||||
|
|
||||||
from six import string_types, iteritems
|
from six import string_types, iteritems
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ class PaymentEntry(AccountsController):
|
|||||||
self.set_exchange_rate()
|
self.set_exchange_rate()
|
||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
self.validate_reference_documents()
|
self.validate_reference_documents()
|
||||||
|
self.set_tax_withholding()
|
||||||
|
self.apply_taxes()
|
||||||
self.set_amounts()
|
self.set_amounts()
|
||||||
self.clear_unallocated_reference_document_rows()
|
self.clear_unallocated_reference_document_rows()
|
||||||
self.validate_payment_against_negative_invoice()
|
self.validate_payment_against_negative_invoice()
|
||||||
@@ -306,11 +309,10 @@ class PaymentEntry(AccountsController):
|
|||||||
for k, v in no_oustanding_refs.items():
|
for k, v in no_oustanding_refs.items():
|
||||||
frappe.msgprint(
|
frappe.msgprint(
|
||||||
_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.")
|
_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.")
|
||||||
.format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount"))
|
.format(k, frappe.bold(", ".join(d.reference_name for d in v)), frappe.bold("negative outstanding amount"))
|
||||||
+ "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
|
+ "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
|
||||||
title=_("Warning"), indicator="orange")
|
title=_("Warning"), indicator="orange")
|
||||||
|
|
||||||
|
|
||||||
def validate_journal_entry(self):
|
def validate_journal_entry(self):
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
if d.allocated_amount and d.reference_doctype == "Journal Entry":
|
if d.allocated_amount and d.reference_doctype == "Journal Entry":
|
||||||
@@ -391,12 +393,110 @@ class PaymentEntry(AccountsController):
|
|||||||
|
|
||||||
self.db_set('status', self.status, update_modified = True)
|
self.db_set('status', self.status, update_modified = True)
|
||||||
|
|
||||||
|
def set_tax_withholding(self):
|
||||||
|
if not self.party_type == 'Supplier':
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.apply_tax_withholding_amount:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.advance_tax_account:
|
||||||
|
frappe.throw(_("Advance TDS account is mandatory for advance TDS deduction"))
|
||||||
|
|
||||||
|
reference_doclist = []
|
||||||
|
net_total = self.paid_amount
|
||||||
|
included_in_paid_amount = 0
|
||||||
|
|
||||||
|
if self.get('references'):
|
||||||
|
for doc in self.get('references'):
|
||||||
|
if doc.reference_doctype == 'Purchase Order':
|
||||||
|
reference_doclist.append(doc.reference_name)
|
||||||
|
|
||||||
|
if reference_doclist:
|
||||||
|
order_amount = frappe.db.get_all('Purchase Order', fields=['sum(net_total)'],
|
||||||
|
filters = {'name': ('in', reference_doclist), 'docstatus': 1,
|
||||||
|
'apply_tds': 1}, as_list=1)
|
||||||
|
|
||||||
|
if order_amount:
|
||||||
|
net_total = order_amount[0][0]
|
||||||
|
included_in_paid_amount = 1
|
||||||
|
|
||||||
|
# Adding args as purchase invoice to get TDS amount
|
||||||
|
args = frappe._dict({
|
||||||
|
'company': self.company,
|
||||||
|
'doctype': 'Purchase Invoice',
|
||||||
|
'supplier': self.party,
|
||||||
|
'posting_date': self.posting_date,
|
||||||
|
'net_total': net_total
|
||||||
|
})
|
||||||
|
|
||||||
|
tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category)
|
||||||
|
|
||||||
|
if not tax_withholding_details:
|
||||||
|
return
|
||||||
|
|
||||||
|
tax_withholding_details.update({
|
||||||
|
'included_in_paid_amount': included_in_paid_amount,
|
||||||
|
'cost_center': self.cost_center or erpnext.get_default_cost_center(self.company)
|
||||||
|
})
|
||||||
|
|
||||||
|
accounts = []
|
||||||
|
for d in self.taxes:
|
||||||
|
if d.account_head == tax_withholding_details.get("account_head"):
|
||||||
|
|
||||||
|
# Preserve user updated included in paid amount
|
||||||
|
if d.included_in_paid_amount:
|
||||||
|
tax_withholding_details.update({'included_in_paid_amount': d.included_in_paid_amount})
|
||||||
|
|
||||||
|
d.update(tax_withholding_details)
|
||||||
|
accounts.append(d.account_head)
|
||||||
|
|
||||||
|
if not accounts or tax_withholding_details.get("account_head") not in accounts:
|
||||||
|
self.append("taxes", tax_withholding_details)
|
||||||
|
|
||||||
|
to_remove = [d for d in self.taxes
|
||||||
|
if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
|
||||||
|
|
||||||
|
for d in to_remove:
|
||||||
|
self.remove(d)
|
||||||
|
|
||||||
|
def apply_taxes(self):
|
||||||
|
self.initialize_taxes()
|
||||||
|
self.determine_exclusive_rate()
|
||||||
|
self.calculate_taxes()
|
||||||
|
|
||||||
def set_amounts(self):
|
def set_amounts(self):
|
||||||
|
self.set_received_amount()
|
||||||
self.set_amounts_in_company_currency()
|
self.set_amounts_in_company_currency()
|
||||||
|
self.set_amounts_after_tax()
|
||||||
self.set_total_allocated_amount()
|
self.set_total_allocated_amount()
|
||||||
self.set_unallocated_amount()
|
self.set_unallocated_amount()
|
||||||
self.set_difference_amount()
|
self.set_difference_amount()
|
||||||
|
|
||||||
|
def set_received_amount(self):
|
||||||
|
self.base_received_amount = self.base_paid_amount
|
||||||
|
|
||||||
|
def set_amounts_after_tax(self):
|
||||||
|
applicable_tax = 0
|
||||||
|
base_applicable_tax = 0
|
||||||
|
for tax in self.get('taxes'):
|
||||||
|
if not tax.included_in_paid_amount:
|
||||||
|
amount = -1 * tax.tax_amount if tax.add_deduct_tax == 'Deduct' else tax.tax_amount
|
||||||
|
base_amount = -1 * tax.base_tax_amount if tax.add_deduct_tax == 'Deduct' else tax.base_tax_amount
|
||||||
|
|
||||||
|
applicable_tax += amount
|
||||||
|
base_applicable_tax += base_amount
|
||||||
|
|
||||||
|
self.paid_amount_after_tax = flt(flt(self.paid_amount) + flt(applicable_tax),
|
||||||
|
self.precision("paid_amount_after_tax"))
|
||||||
|
self.base_paid_amount_after_tax = flt(flt(self.paid_amount_after_tax) * flt(self.source_exchange_rate),
|
||||||
|
self.precision("base_paid_amount_after_tax"))
|
||||||
|
|
||||||
|
self.received_amount_after_tax = flt(flt(self.received_amount) + flt(applicable_tax),
|
||||||
|
self.precision("paid_amount_after_tax"))
|
||||||
|
self.base_received_amount_after_tax = flt(flt(self.received_amount_after_tax) * flt(self.target_exchange_rate),
|
||||||
|
self.precision("base_paid_amount_after_tax"))
|
||||||
|
|
||||||
def set_amounts_in_company_currency(self):
|
def set_amounts_in_company_currency(self):
|
||||||
self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0
|
self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0
|
||||||
if self.paid_amount:
|
if self.paid_amount:
|
||||||
@@ -424,17 +524,17 @@ class PaymentEntry(AccountsController):
|
|||||||
def set_unallocated_amount(self):
|
def set_unallocated_amount(self):
|
||||||
self.unallocated_amount = 0
|
self.unallocated_amount = 0
|
||||||
if self.party:
|
if self.party:
|
||||||
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
|
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
|
||||||
if self.payment_type == "Receive" \
|
if self.payment_type == "Receive" \
|
||||||
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
|
and self.base_total_allocated_amount < self.base_received_amount_after_tax + total_deductions \
|
||||||
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
|
and self.total_allocated_amount < self.paid_amount_after_tax + (total_deductions / self.source_exchange_rate):
|
||||||
self.unallocated_amount = (self.base_received_amount + total_deductions -
|
self.unallocated_amount = (self.received_amount_after_tax + total_deductions -
|
||||||
self.base_total_allocated_amount) / self.source_exchange_rate
|
self.base_total_allocated_amount) / self.source_exchange_rate
|
||||||
elif self.payment_type == "Pay" \
|
elif self.payment_type == "Pay" \
|
||||||
and self.base_total_allocated_amount < (self.base_paid_amount - total_deductions) \
|
and self.base_total_allocated_amount < (self.base_paid_amount_after_tax - total_deductions) \
|
||||||
and self.total_allocated_amount < self.received_amount + (total_deductions / self.target_exchange_rate):
|
and self.total_allocated_amount < self.received_amount_after_tax + (total_deductions / self.target_exchange_rate):
|
||||||
self.unallocated_amount = (self.base_paid_amount - (total_deductions +
|
self.unallocated_amount = (self.base_paid_amount_after_tax - (total_deductions +
|
||||||
self.base_total_allocated_amount)) / self.target_exchange_rate
|
self.base_total_allocated_amount)) / self.target_exchange_rate
|
||||||
|
|
||||||
def set_difference_amount(self):
|
def set_difference_amount(self):
|
||||||
base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
|
base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
|
||||||
@@ -443,13 +543,13 @@ class PaymentEntry(AccountsController):
|
|||||||
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
|
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
|
||||||
|
|
||||||
if self.payment_type == "Receive":
|
if self.payment_type == "Receive":
|
||||||
self.difference_amount = base_party_amount - self.base_received_amount
|
self.difference_amount = base_party_amount - self.base_received_amount_after_tax
|
||||||
elif self.payment_type == "Pay":
|
elif self.payment_type == "Pay":
|
||||||
self.difference_amount = self.base_paid_amount - base_party_amount
|
self.difference_amount = self.base_paid_amount_after_tax - base_party_amount
|
||||||
else:
|
else:
|
||||||
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
|
self.difference_amount = self.base_paid_amount_after_tax - flt(self.base_received_amount_after_tax)
|
||||||
|
|
||||||
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
|
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
|
||||||
|
|
||||||
self.difference_amount = flt(self.difference_amount - total_deductions,
|
self.difference_amount = flt(self.difference_amount - total_deductions,
|
||||||
self.precision("difference_amount"))
|
self.precision("difference_amount"))
|
||||||
@@ -465,8 +565,8 @@ class PaymentEntry(AccountsController):
|
|||||||
if ((self.payment_type=="Pay" and self.party_type=="Customer")
|
if ((self.payment_type=="Pay" and self.party_type=="Customer")
|
||||||
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
|
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
|
||||||
|
|
||||||
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
|
total_negative_outstanding = sum(abs(flt(d.outstanding_amount))
|
||||||
for d in self.get("references") if flt(d.outstanding_amount) < 0])
|
for d in self.get("references") if flt(d.outstanding_amount) < 0)
|
||||||
|
|
||||||
paid_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
|
paid_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
|
||||||
additional_charges = sum([flt(d.amount) for d in self.deductions])
|
additional_charges = sum([flt(d.amount) for d in self.deductions])
|
||||||
@@ -537,6 +637,7 @@ class PaymentEntry(AccountsController):
|
|||||||
self.add_party_gl_entries(gl_entries)
|
self.add_party_gl_entries(gl_entries)
|
||||||
self.add_bank_gl_entries(gl_entries)
|
self.add_bank_gl_entries(gl_entries)
|
||||||
self.add_deductions_gl_entries(gl_entries)
|
self.add_deductions_gl_entries(gl_entries)
|
||||||
|
self.add_tax_gl_entries(gl_entries)
|
||||||
|
|
||||||
make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
|
make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
|
||||||
|
|
||||||
@@ -576,7 +677,7 @@ class PaymentEntry(AccountsController):
|
|||||||
gl_entries.append(gle)
|
gl_entries.append(gle)
|
||||||
|
|
||||||
if self.unallocated_amount:
|
if self.unallocated_amount:
|
||||||
base_unallocated_amount = base_unallocated_amount = self.unallocated_amount * \
|
base_unallocated_amount = self.unallocated_amount * \
|
||||||
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
|
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
|
||||||
|
|
||||||
gle = party_gl_dict.copy()
|
gle = party_gl_dict.copy()
|
||||||
@@ -595,8 +696,8 @@ class PaymentEntry(AccountsController):
|
|||||||
"account": self.paid_from,
|
"account": self.paid_from,
|
||||||
"account_currency": self.paid_from_account_currency,
|
"account_currency": self.paid_from_account_currency,
|
||||||
"against": self.party if self.payment_type=="Pay" else self.paid_to,
|
"against": self.party if self.payment_type=="Pay" else self.paid_to,
|
||||||
"credit_in_account_currency": self.paid_amount,
|
"credit_in_account_currency": self.paid_amount_after_tax,
|
||||||
"credit": self.base_paid_amount,
|
"credit": self.base_paid_amount_after_tax,
|
||||||
"cost_center": self.cost_center
|
"cost_center": self.cost_center
|
||||||
}, item=self)
|
}, item=self)
|
||||||
)
|
)
|
||||||
@@ -606,12 +707,48 @@ class PaymentEntry(AccountsController):
|
|||||||
"account": self.paid_to,
|
"account": self.paid_to,
|
||||||
"account_currency": self.paid_to_account_currency,
|
"account_currency": self.paid_to_account_currency,
|
||||||
"against": self.party if self.payment_type=="Receive" else self.paid_from,
|
"against": self.party if self.payment_type=="Receive" else self.paid_from,
|
||||||
"debit_in_account_currency": self.received_amount,
|
"debit_in_account_currency": self.received_amount_after_tax,
|
||||||
"debit": self.base_received_amount,
|
"debit": self.base_received_amount_after_tax,
|
||||||
"cost_center": self.cost_center
|
"cost_center": self.cost_center
|
||||||
}, item=self)
|
}, item=self)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def add_tax_gl_entries(self, gl_entries):
|
||||||
|
for d in self.get('taxes'):
|
||||||
|
account_currency = get_account_currency(d.account_head)
|
||||||
|
if account_currency != self.company_currency:
|
||||||
|
frappe.throw(_("Currency for {0} must be {1}").format(d.account_head, self.company_currency))
|
||||||
|
|
||||||
|
if (self.payment_type == 'Pay' and self.advance_tax_account) or self.payment_type == 'Receive':
|
||||||
|
dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
|
||||||
|
elif (self.payment_type == 'Receive' and self.advance_tax_account) or self.payment_type == 'Pay':
|
||||||
|
dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
|
||||||
|
|
||||||
|
payment_or_advance_account = self.get_party_account_for_taxes()
|
||||||
|
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": d.account_head,
|
||||||
|
"against": self.party if self.payment_type=="Receive" else self.paid_from,
|
||||||
|
dr_or_cr: d.base_tax_amount,
|
||||||
|
dr_or_cr + "_in_account_currency": d.base_tax_amount
|
||||||
|
if account_currency==self.company_currency
|
||||||
|
else d.tax_amount,
|
||||||
|
"cost_center": d.cost_center
|
||||||
|
}, account_currency, item=d))
|
||||||
|
|
||||||
|
#Intentionally use -1 to get net values in party account
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": payment_or_advance_account,
|
||||||
|
"against": self.party if self.payment_type=="Receive" else self.paid_from,
|
||||||
|
dr_or_cr: -1 * d.base_tax_amount,
|
||||||
|
dr_or_cr + "_in_account_currency": -1*d.base_tax_amount
|
||||||
|
if account_currency==self.company_currency
|
||||||
|
else d.tax_amount,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
}, account_currency, item=d))
|
||||||
|
|
||||||
def add_deductions_gl_entries(self, gl_entries):
|
def add_deductions_gl_entries(self, gl_entries):
|
||||||
for d in self.get("deductions"):
|
for d in self.get("deductions"):
|
||||||
if d.amount:
|
if d.amount:
|
||||||
@@ -630,6 +767,14 @@ class PaymentEntry(AccountsController):
|
|||||||
}, item=d)
|
}, item=d)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_party_account_for_taxes(self):
|
||||||
|
if self.advance_tax_account:
|
||||||
|
return self.advance_tax_account
|
||||||
|
elif self.payment_type == 'Pay':
|
||||||
|
return self.paid_from
|
||||||
|
elif self.payment_type == 'Receive':
|
||||||
|
return self.paid_to
|
||||||
|
|
||||||
def update_advance_paid(self):
|
def update_advance_paid(self):
|
||||||
if self.payment_type in ("Receive", "Pay") and self.party:
|
if self.payment_type in ("Receive", "Pay") and self.party:
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
@@ -676,6 +821,121 @@ class PaymentEntry(AccountsController):
|
|||||||
self.append('deductions', row)
|
self.append('deductions', row)
|
||||||
self.set_unallocated_amount()
|
self.set_unallocated_amount()
|
||||||
|
|
||||||
|
def initialize_taxes(self):
|
||||||
|
for tax in self.get("taxes"):
|
||||||
|
tax_fields = ["total", "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
|
||||||
|
|
||||||
|
if tax.charge_type != "Actual":
|
||||||
|
tax_fields.append("tax_amount")
|
||||||
|
|
||||||
|
for fieldname in tax_fields:
|
||||||
|
tax.set(fieldname, 0.0)
|
||||||
|
|
||||||
|
self.paid_amount_after_tax = self.paid_amount
|
||||||
|
|
||||||
|
def determine_exclusive_rate(self):
|
||||||
|
if not any((cint(tax.included_in_paid_amount) for tax in self.get("taxes"))):
|
||||||
|
return
|
||||||
|
|
||||||
|
cumulated_tax_fraction = 0
|
||||||
|
for i, tax in enumerate(self.get("taxes")):
|
||||||
|
tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax)
|
||||||
|
if i==0:
|
||||||
|
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
|
||||||
|
else:
|
||||||
|
tax.grand_total_fraction_for_current_item = \
|
||||||
|
self.get("taxes")[i-1].grand_total_fraction_for_current_item \
|
||||||
|
+ tax.tax_fraction_for_current_item
|
||||||
|
|
||||||
|
cumulated_tax_fraction += tax.tax_fraction_for_current_item
|
||||||
|
|
||||||
|
self.paid_amount_after_tax = flt(self.paid_amount/(1+cumulated_tax_fraction))
|
||||||
|
|
||||||
|
def calculate_taxes(self):
|
||||||
|
self.total_taxes_and_charges = 0.0
|
||||||
|
self.base_total_taxes_and_charges = 0.0
|
||||||
|
|
||||||
|
actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
|
||||||
|
for tax in self.get("taxes") if tax.charge_type == "Actual"])
|
||||||
|
|
||||||
|
for i, tax in enumerate(self.get('taxes')):
|
||||||
|
current_tax_amount = self.get_current_tax_amount(tax)
|
||||||
|
|
||||||
|
if tax.charge_type == "Actual":
|
||||||
|
actual_tax_dict[tax.idx] -= current_tax_amount
|
||||||
|
if i == len(self.get("taxes")) - 1:
|
||||||
|
current_tax_amount += actual_tax_dict[tax.idx]
|
||||||
|
|
||||||
|
tax.tax_amount = current_tax_amount
|
||||||
|
tax.base_tax_amount = tax.tax_amount * self.source_exchange_rate
|
||||||
|
|
||||||
|
if tax.add_deduct_tax == "Deduct":
|
||||||
|
current_tax_amount *= -1.0
|
||||||
|
else:
|
||||||
|
current_tax_amount *= 1.0
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
tax.total = flt(self.paid_amount_after_tax + current_tax_amount, self.precision("total", tax))
|
||||||
|
else:
|
||||||
|
tax.total = flt(self.get('taxes')[i-1].total + current_tax_amount, self.precision("total", tax))
|
||||||
|
|
||||||
|
tax.base_total = tax.total * self.source_exchange_rate
|
||||||
|
|
||||||
|
self.total_taxes_and_charges += current_tax_amount
|
||||||
|
self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate
|
||||||
|
|
||||||
|
if self.get('taxes'):
|
||||||
|
self.paid_amount_after_tax = self.get('taxes')[-1].base_total
|
||||||
|
|
||||||
|
def get_current_tax_amount(self, tax):
|
||||||
|
tax_rate = tax.rate
|
||||||
|
|
||||||
|
# To set row_id by default as previous row.
|
||||||
|
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"]:
|
||||||
|
if tax.idx == 1:
|
||||||
|
frappe.throw(_("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"))
|
||||||
|
|
||||||
|
if not tax.row_id:
|
||||||
|
tax.row_id = tax.idx - 1
|
||||||
|
|
||||||
|
if tax.charge_type == "Actual":
|
||||||
|
current_tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax))
|
||||||
|
elif tax.charge_type == "On Paid Amount":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * self.paid_amount_after_tax
|
||||||
|
elif tax.charge_type == "On Previous Row Amount":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * \
|
||||||
|
self.get('taxes')[cint(tax.row_id) - 1].tax_amount
|
||||||
|
|
||||||
|
elif tax.charge_type == "On Previous Row Total":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * \
|
||||||
|
self.get('taxes')[cint(tax.row_id) - 1].total
|
||||||
|
|
||||||
|
return current_tax_amount
|
||||||
|
|
||||||
|
def get_current_tax_fraction(self, tax):
|
||||||
|
current_tax_fraction = 0
|
||||||
|
|
||||||
|
if cint(tax.included_in_paid_amount):
|
||||||
|
tax_rate = tax.rate
|
||||||
|
|
||||||
|
if tax.charge_type == 'Actual':
|
||||||
|
current_tax_fraction = tax.tax_amount/ (self.paid_amount_after_tax + tax.tax_amount)
|
||||||
|
elif tax.charge_type == "On Paid Amount":
|
||||||
|
current_tax_fraction = tax_rate / 100.0
|
||||||
|
|
||||||
|
elif tax.charge_type == "On Previous Row Amount":
|
||||||
|
current_tax_fraction = (tax_rate / 100.0) * \
|
||||||
|
self.get("taxes")[cint(tax.row_id) - 1].tax_fraction_for_current_item
|
||||||
|
|
||||||
|
elif tax.charge_type == "On Previous Row Total":
|
||||||
|
current_tax_fraction = (tax_rate / 100.0) * \
|
||||||
|
self.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
|
||||||
|
|
||||||
|
if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct":
|
||||||
|
current_tax_fraction *= -1.0
|
||||||
|
|
||||||
|
return current_tax_fraction
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_outstanding_reference_documents(args):
|
def get_outstanding_reference_documents(args):
|
||||||
|
|
||||||
@@ -1241,6 +1501,13 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
})
|
})
|
||||||
pe.set_difference_amount()
|
pe.set_difference_amount()
|
||||||
|
|
||||||
|
if doc.doctype == 'Purchase Order' and doc.apply_tds:
|
||||||
|
pe.apply_tax_withholding_amount = 1
|
||||||
|
pe.tax_withholding_category = doc.tax_withholding_category
|
||||||
|
|
||||||
|
if not pe.advance_tax_account:
|
||||||
|
pe.advance_tax_account = frappe.db.get_value('Company', pe.company, 'unrealized_profit_loss_account')
|
||||||
|
|
||||||
return pe
|
return pe
|
||||||
|
|
||||||
def get_bank_cash_account(doc, bank_account):
|
def get_bank_cash_account(doc, bank_account):
|
||||||
|
|||||||
@@ -1,140 +1,70 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2016-06-15 15:56:30.815503",
|
"creation": "2016-06-15 15:56:30.815503",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"field_order": [
|
||||||
|
"account",
|
||||||
|
"cost_center",
|
||||||
|
"amount",
|
||||||
|
"column_break_2",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "account",
|
"fieldname": "account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Account",
|
"label": "Account",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"show_days": 1,
|
||||||
"set_only_once": 0,
|
"show_seconds": 1
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Cost Center",
|
"label": "Cost Center",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Cost Center",
|
"options": "Cost Center",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"show_days": 1,
|
||||||
"set_only_once": 0,
|
"show_seconds": 1
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amount",
|
"fieldname": "amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amount",
|
"label": "Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"show_days": 1,
|
||||||
"set_only_once": 0,
|
"show_seconds": 1
|
||||||
"translatable": 0,
|
},
|
||||||
"unique": 0
|
{
|
||||||
|
"fieldname": "column_break_2",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Description",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"index_web_pages_for_search": 1,
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2019-01-07 16:52:07.040146",
|
"modified": "2020-09-12 20:38:08.110674",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Entry Deduction",
|
"name": "Payment Entry Deduction",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ class PaymentRequest(Document):
|
|||||||
if not data_of_completed_requests:
|
if not data_of_completed_requests:
|
||||||
return self.grand_total
|
return self.grand_total
|
||||||
|
|
||||||
request_amounts = sum([json.loads(d).get('request_amount') for d in data_of_completed_requests])
|
request_amounts = sum(json.loads(d).get('request_amount') for d in data_of_completed_requests)
|
||||||
return request_amounts
|
return request_amounts
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ from frappe.utils import cint, flt, get_link_to_form, getdate, today, fmt_money
|
|||||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||||
|
|
||||||
apply_on_table = {
|
apply_on_table = {
|
||||||
'Item Code': 'items',
|
'Item Code': 'items',
|
||||||
'Item Group': 'item_groups',
|
'Item Group': 'item_groups',
|
||||||
'Brand': 'brands'
|
'Brand': 'brands'
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_pricing_rules(args, doc=None):
|
def get_pricing_rules(args, doc=None):
|
||||||
@@ -183,7 +183,7 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
|||||||
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
|
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
|
||||||
table=table,
|
table=table,
|
||||||
field=field,
|
field=field,
|
||||||
parent_groups=", ".join([frappe.db.escape(d) for d in parent_groups])
|
parent_groups=", ".join(frappe.db.escape(d) for d in parent_groups)
|
||||||
)
|
)
|
||||||
|
|
||||||
frappe.flags.tree_conditions[key] = condition
|
frappe.flags.tree_conditions[key] = condition
|
||||||
@@ -264,7 +264,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
|||||||
|
|
||||||
# find pricing rule with highest priority
|
# find pricing rule with highest priority
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
max_priority = max([cint(p.priority) for p in pricing_rules])
|
max_priority = max(cint(p.priority) for p in pricing_rules)
|
||||||
if max_priority:
|
if max_priority:
|
||||||
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
|
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
|
||||||
|
|
||||||
@@ -272,14 +272,14 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
|||||||
pricing_rules = list(pricing_rules)
|
pricing_rules = list(pricing_rules)
|
||||||
|
|
||||||
if len(pricing_rules) > 1:
|
if len(pricing_rules) > 1:
|
||||||
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
rate_or_discount = list(set(d.rate_or_discount for d in pricing_rules))
|
||||||
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
||||||
pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
|
pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
|
||||||
or pricing_rules
|
or pricing_rules
|
||||||
|
|
||||||
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
||||||
frappe.throw(_("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}")
|
frappe.throw(_("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}")
|
||||||
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
|
.format("\n".join(d.name for d in pricing_rules)), MultiplePricingRuleConflict)
|
||||||
elif pricing_rules:
|
elif pricing_rules:
|
||||||
return pricing_rules[0]
|
return pricing_rules[0]
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
|||||||
|
|
||||||
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||||
if pricing_rule_args:
|
if pricing_rule_args:
|
||||||
items = tuple([(d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item])
|
items = tuple((d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item)
|
||||||
|
|
||||||
for args in pricing_rule_args:
|
for args in pricing_rule_args:
|
||||||
if not items or (args.get('item_code'), args.get('pricing_rules')) not in items:
|
if not items or (args.get('item_code'), args.get('pricing_rules')) not in items:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -68,9 +68,6 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
super(PurchaseInvoice, self).validate()
|
super(PurchaseInvoice, self).validate()
|
||||||
|
|
||||||
# apply tax withholding only if checked and applicable
|
|
||||||
self.set_tax_withholding()
|
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
self.po_required()
|
self.po_required()
|
||||||
self.pr_required()
|
self.pr_required()
|
||||||
@@ -251,11 +248,9 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
if self.update_stock and (not item.from_warehouse):
|
if self.update_stock and (not item.from_warehouse):
|
||||||
if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]:
|
if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]:
|
||||||
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]))
|
msg = _("Row {0}: Expense Head changed to {1} because account {2} is not linked to warehouse {3} or it is not the default inventory account").format(
|
||||||
msg += _("because account {} is not linked to warehouse {} ").format(frappe.bold(item.expense_account), frappe.bold(item.warehouse))
|
item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]), frappe.bold(item.expense_account), frappe.bold(item.warehouse))
|
||||||
msg += _("or it is not the default inventory account")
|
|
||||||
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
||||||
|
|
||||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||||
else:
|
else:
|
||||||
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
||||||
@@ -266,8 +261,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
if negative_expense_booked_in_pr:
|
if negative_expense_booked_in_pr:
|
||||||
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
||||||
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
|
msg = _("Row {0}: Expense Head changed to {1} because expense is booked against this account in Purchase Receipt {2}").format(
|
||||||
msg += _("because expense is booked against this account in Purchase Receipt {}").format(frappe.bold(item.purchase_receipt))
|
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt))
|
||||||
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
||||||
|
|
||||||
item.expense_account = stock_not_billed_account
|
item.expense_account = stock_not_billed_account
|
||||||
@@ -275,8 +270,9 @@ class PurchaseInvoice(BuyingController):
|
|||||||
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
|
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
|
||||||
# This is done in cases when Purchase Invoice is created before Purchase Receipt
|
# This is done in cases when Purchase Invoice is created before Purchase Receipt
|
||||||
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
||||||
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
|
msg = _("Row {0}: Expense Head changed to {1} as no Purchase Receipt is created against Item {2}.").format(
|
||||||
msg += _("as no Purchase Receipt is created against Item {}. ").format(frappe.bold(item.item_code))
|
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.item_code))
|
||||||
|
msg += "<br>"
|
||||||
msg += _("This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice")
|
msg += _("This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice")
|
||||||
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
||||||
|
|
||||||
@@ -308,8 +304,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if not d.purchase_order:
|
if not d.purchase_order:
|
||||||
msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code))
|
msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code))
|
||||||
msg += "<br><br>"
|
msg += "<br><br>"
|
||||||
msg += _("To submit the invoice without purchase order please set {} ").format(frappe.bold(_('Purchase Order Required')))
|
msg += _("To submit the invoice without purchase order please set {0} as {1} in {2}").format(
|
||||||
msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
|
frappe.bold(_('Purchase Order Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
|
||||||
throw(msg, title=_("Mandatory Purchase Order"))
|
throw(msg, title=_("Mandatory Purchase Order"))
|
||||||
|
|
||||||
def pr_required(self):
|
def pr_required(self):
|
||||||
@@ -323,8 +319,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if not d.purchase_receipt and d.item_code in stock_items:
|
if not d.purchase_receipt and d.item_code in stock_items:
|
||||||
msg = _("Purchase Receipt Required for item {}").format(frappe.bold(d.item_code))
|
msg = _("Purchase Receipt Required for item {}").format(frappe.bold(d.item_code))
|
||||||
msg += "<br><br>"
|
msg += "<br><br>"
|
||||||
msg += _("To submit the invoice without purchase receipt please set {} ").format(frappe.bold(_('Purchase Receipt Required')))
|
msg += _("To submit the invoice without purchase receipt please set {0} as {1} in {2}").format(
|
||||||
msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
|
frappe.bold(_('Purchase Receipt Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
|
||||||
throw(msg, title=_("Mandatory Purchase Receipt"))
|
throw(msg, title=_("Mandatory Purchase Receipt"))
|
||||||
|
|
||||||
def validate_write_off_account(self):
|
def validate_write_off_account(self):
|
||||||
@@ -456,6 +452,8 @@ class PurchaseInvoice(BuyingController):
|
|||||||
self.make_tax_gl_entries(gl_entries)
|
self.make_tax_gl_entries(gl_entries)
|
||||||
self.make_internal_transfer_gl_entries(gl_entries)
|
self.make_internal_transfer_gl_entries(gl_entries)
|
||||||
|
|
||||||
|
self.allocate_advance_taxes(gl_entries)
|
||||||
|
|
||||||
gl_entries = make_regional_gl_entries(gl_entries, self)
|
gl_entries = make_regional_gl_entries(gl_entries, self)
|
||||||
|
|
||||||
gl_entries = merge_similar_entries(gl_entries)
|
gl_entries = merge_similar_entries(gl_entries)
|
||||||
@@ -1090,6 +1088,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
for d in self.taxes:
|
for d in self.taxes:
|
||||||
if d.account_head == tax_withholding_details.get("account_head"):
|
if d.account_head == tax_withholding_details.get("account_head"):
|
||||||
d.update(tax_withholding_details)
|
d.update(tax_withholding_details)
|
||||||
|
|
||||||
accounts.append(d.account_head)
|
accounts.append(d.account_head)
|
||||||
|
|
||||||
if not accounts or tax_withholding_details.get("account_head") not in accounts:
|
if not accounts or tax_withholding_details.get("account_head") not in accounts:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_tra
|
|||||||
from erpnext.projects.doctype.project.test_project import make_project
|
from erpnext.projects.doctype.project.test_project import make_project
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||||
from erpnext.stock.doctype.item.test_item import create_item
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
|
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||||
|
|
||||||
test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"]
|
test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"]
|
||||||
test_ignore = ["Serial No"]
|
test_ignore = ["Serial No"]
|
||||||
@@ -631,7 +632,7 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(pi.get("supplied_items")), 2)
|
self.assertEqual(len(pi.get("supplied_items")), 2)
|
||||||
|
|
||||||
rm_supp_cost = sum([d.amount for d in pi.get("supplied_items")])
|
rm_supp_cost = sum(d.amount for d in pi.get("supplied_items"))
|
||||||
self.assertEqual(flt(pi.get("items")[0].rm_supp_cost, 2), flt(rm_supp_cost, 2))
|
self.assertEqual(flt(pi.get("items")[0].rm_supp_cost, 2), flt(rm_supp_cost, 2))
|
||||||
|
|
||||||
def test_rejected_serial_no(self):
|
def test_rejected_serial_no(self):
|
||||||
@@ -950,6 +951,102 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
acc_settings.submit_journal_entriessubmit_journal_entries = 0
|
acc_settings.submit_journal_entriessubmit_journal_entries = 0
|
||||||
acc_settings.save()
|
acc_settings.save()
|
||||||
|
|
||||||
|
def test_purchase_invoice_advance_taxes(self):
|
||||||
|
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
|
||||||
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
|
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_purchase_invoice
|
||||||
|
|
||||||
|
# create a new supplier to test
|
||||||
|
supplier = create_supplier(supplier_name = '_Test TDS Advance Supplier',
|
||||||
|
tax_withholding_category = 'TDS - 194 - Dividends - Individual')
|
||||||
|
|
||||||
|
# Update tax withholding category with current fiscal year and rate details
|
||||||
|
update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate())
|
||||||
|
|
||||||
|
# Create Purchase Order with TDS applied
|
||||||
|
po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000)
|
||||||
|
po.apply_tds = 1
|
||||||
|
po.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
|
||||||
|
po.save()
|
||||||
|
po.submit()
|
||||||
|
|
||||||
|
# Update Unrealized Profit / Loss Account which is used as default advance tax account
|
||||||
|
frappe.db.set_value('Company', '_Test Company', 'unrealized_profit_loss_account', '_Test Account Excise Duty - _TC')
|
||||||
|
|
||||||
|
# Create Payment Entry Against the order
|
||||||
|
payment_entry = get_payment_entry(dt='Purchase Order', dn=po.name)
|
||||||
|
payment_entry.paid_from = 'Cash - _TC'
|
||||||
|
payment_entry.save()
|
||||||
|
payment_entry.submit()
|
||||||
|
|
||||||
|
# Check GLE for Payment Entry
|
||||||
|
expected_gle = [
|
||||||
|
['_Test Account Excise Duty - _TC', 3000, 0],
|
||||||
|
['Cash - _TC', 0, 27000],
|
||||||
|
['Creditors - _TC', 27000, 0],
|
||||||
|
['TDS Payable - _TC', 0, 3000],
|
||||||
|
]
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||||
|
from `tabGL Entry`
|
||||||
|
where voucher_type='Payment Entry' and voucher_no=%s
|
||||||
|
order by account asc""", (payment_entry.name), as_dict=1)
|
||||||
|
|
||||||
|
for i, gle in enumerate(gl_entries):
|
||||||
|
self.assertEqual(expected_gle[i][0], gle.account)
|
||||||
|
self.assertEqual(expected_gle[i][1], gle.debit)
|
||||||
|
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||||
|
|
||||||
|
# Create Purchase Invoice against Purchase Order
|
||||||
|
purchase_invoice = get_mapped_purchase_invoice(po.name)
|
||||||
|
purchase_invoice.allocate_advances_automatically = 1
|
||||||
|
purchase_invoice.items[0].expense_account = '_Test Account Cost for Goods Sold - _TC'
|
||||||
|
purchase_invoice.save()
|
||||||
|
purchase_invoice.submit()
|
||||||
|
|
||||||
|
# Check GLE for Purchase Invoice
|
||||||
|
# Zero net effect on final TDS Payable on invoice
|
||||||
|
expected_gle = [
|
||||||
|
['_Test Account Cost for Goods Sold - _TC', 30000, 0],
|
||||||
|
['_Test Account Excise Duty - _TC', 0, 3000],
|
||||||
|
['Creditors - _TC', 0, 27000],
|
||||||
|
['TDS Payable - _TC', 3000, 3000]
|
||||||
|
]
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||||
|
from `tabGL Entry`
|
||||||
|
where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||||
|
order by account asc""", (purchase_invoice.name), as_dict=1)
|
||||||
|
|
||||||
|
for i, gle in enumerate(gl_entries):
|
||||||
|
self.assertEqual(expected_gle[i][0], gle.account)
|
||||||
|
self.assertEqual(expected_gle[i][1], gle.debit)
|
||||||
|
self.assertEqual(expected_gle[i][2], gle.credit)
|
||||||
|
|
||||||
|
def update_tax_witholding_category(company, account, date):
|
||||||
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
|
fiscal_year = get_fiscal_year(date=date, company=company)
|
||||||
|
|
||||||
|
if not frappe.db.get_value('Tax Withholding Rate',
|
||||||
|
{'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}):
|
||||||
|
tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual')
|
||||||
|
tds_category.append('rates', {
|
||||||
|
'fiscal_year': fiscal_year[0],
|
||||||
|
'tax_withholding_rate': 10,
|
||||||
|
'single_threshold': 2500,
|
||||||
|
'cumulative_threshold': 0
|
||||||
|
})
|
||||||
|
tds_category.save()
|
||||||
|
|
||||||
|
if not frappe.db.get_value('Tax Withholding Account',
|
||||||
|
{'parent': 'TDS - 194 - Dividends - Individual', 'account': account}):
|
||||||
|
tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual')
|
||||||
|
tds_category.append('accounts', {
|
||||||
|
'company': company,
|
||||||
|
'account': account
|
||||||
|
})
|
||||||
|
tds_category.save()
|
||||||
|
|
||||||
def unlink_payment_on_cancel_of_invoice(enable=1):
|
def unlink_payment_on_cancel_of_invoice(enable=1):
|
||||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"charge_type",
|
"charge_type",
|
||||||
"row_id",
|
"row_id",
|
||||||
"included_in_print_rate",
|
"included_in_print_rate",
|
||||||
|
"included_in_paid_amount",
|
||||||
"col_break1",
|
"col_break1",
|
||||||
"account_head",
|
"account_head",
|
||||||
"description",
|
"description",
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
"section_break_9",
|
"section_break_9",
|
||||||
|
"currency",
|
||||||
"tax_amount",
|
"tax_amount",
|
||||||
"tax_amount_after_discount_amount",
|
"tax_amount_after_discount_amount",
|
||||||
"total",
|
"total",
|
||||||
@@ -205,12 +207,27 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "account_head.account_currency",
|
||||||
|
"fieldname": "currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Account Currency",
|
||||||
|
"options": "Currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry",
|
||||||
|
"fieldname": "included_in_paid_amount",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Considered In Paid Amount"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-18 17:26:09.703215",
|
"modified": "2021-06-09 11:48:25.335733",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Taxes and Charges",
|
"name": "Purchase Taxes and Charges",
|
||||||
|
|||||||
@@ -842,6 +842,8 @@ class SalesInvoice(SellingController):
|
|||||||
self.make_tax_gl_entries(gl_entries)
|
self.make_tax_gl_entries(gl_entries)
|
||||||
self.make_internal_transfer_gl_entries(gl_entries)
|
self.make_internal_transfer_gl_entries(gl_entries)
|
||||||
|
|
||||||
|
self.allocate_advance_taxes(gl_entries)
|
||||||
|
|
||||||
self.make_item_gl_entries(gl_entries)
|
self.make_item_gl_entries(gl_entries)
|
||||||
|
|
||||||
# merge gl entries before adding pos entries
|
# merge gl entries before adding pos entries
|
||||||
|
|||||||
@@ -1985,6 +1985,33 @@ def get_sales_invoice_for_e_invoice():
|
|||||||
|
|
||||||
return si
|
return si
|
||||||
|
|
||||||
|
def test_item_tax_net_range(self):
|
||||||
|
item = create_item("T Shirt")
|
||||||
|
|
||||||
|
item.set('taxes', [])
|
||||||
|
item.append("taxes", {
|
||||||
|
"item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
|
||||||
|
"minimum_net_rate": 0,
|
||||||
|
"maximum_net_rate": 500
|
||||||
|
})
|
||||||
|
|
||||||
|
item.append("taxes", {
|
||||||
|
"item_tax_template": "_Test Account Excise Duty @ 12 - _TC",
|
||||||
|
"minimum_net_rate": 501,
|
||||||
|
"maximum_net_rate": 1000
|
||||||
|
})
|
||||||
|
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True)
|
||||||
|
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC")
|
||||||
|
|
||||||
|
# Apply discount
|
||||||
|
sales_invoice.apply_discount_on = 'Net Total'
|
||||||
|
sales_invoice.discount_amount = 300
|
||||||
|
sales_invoice.save()
|
||||||
|
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
|
||||||
|
|
||||||
def make_test_address_for_ewaybill():
|
def make_test_address_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({
|
||||||
@@ -2107,27 +2134,6 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
|
|||||||
doc.assertEqual(expected_gle[i][2], gle.credit)
|
doc.assertEqual(expected_gle[i][2], gle.credit)
|
||||||
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||||
|
|
||||||
def test_item_tax_validity(self):
|
|
||||||
item = frappe.get_doc("Item", "_Test Item 2")
|
|
||||||
|
|
||||||
if item.taxes:
|
|
||||||
item.taxes = []
|
|
||||||
item.save()
|
|
||||||
|
|
||||||
item.append("taxes", {
|
|
||||||
"item_tax_template": "_Test Item Tax Template 1 - _TC",
|
|
||||||
"valid_from": add_days(nowdate(), 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
item.save()
|
|
||||||
|
|
||||||
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
|
|
||||||
sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC"
|
|
||||||
self.assertRaises(frappe.ValidationError, sales_invoice.save)
|
|
||||||
|
|
||||||
item.taxes = []
|
|
||||||
item.save()
|
|
||||||
|
|
||||||
def create_sales_invoice(**args):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2013-04-24 11:39:32",
|
"creation": "2013-04-24 11:39:32",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"charge_type",
|
"charge_type",
|
||||||
"row_id",
|
"row_id",
|
||||||
@@ -10,12 +12,14 @@
|
|||||||
"col_break_1",
|
"col_break_1",
|
||||||
"description",
|
"description",
|
||||||
"included_in_print_rate",
|
"included_in_print_rate",
|
||||||
|
"included_in_paid_amount",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
"section_break_8",
|
"section_break_8",
|
||||||
"rate",
|
"rate",
|
||||||
"section_break_9",
|
"section_break_9",
|
||||||
|
"currency",
|
||||||
"tax_amount",
|
"tax_amount",
|
||||||
"total",
|
"total",
|
||||||
"tax_amount_after_discount_amount",
|
"tax_amount_after_discount_amount",
|
||||||
@@ -23,8 +27,7 @@
|
|||||||
"base_tax_amount",
|
"base_tax_amount",
|
||||||
"base_total",
|
"base_total",
|
||||||
"base_tax_amount_after_discount_amount",
|
"base_tax_amount_after_discount_amount",
|
||||||
"item_wise_tax_detail",
|
"item_wise_tax_detail"
|
||||||
"parenttype"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -173,17 +176,6 @@
|
|||||||
"oldfieldtype": "Small Text",
|
"oldfieldtype": "Small Text",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "parenttype",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1,
|
|
||||||
"in_filter": 1,
|
|
||||||
"label": "Parenttype",
|
|
||||||
"oldfieldname": "parenttype",
|
|
||||||
"oldfieldtype": "Data",
|
|
||||||
"print_hide": 1,
|
|
||||||
"search_index": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "accounting_dimensions_section",
|
"fieldname": "accounting_dimensions_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@@ -192,15 +184,33 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "account_head.account_currency",
|
||||||
|
"fieldname": "currency",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Account Currency",
|
||||||
|
"options": "Currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry",
|
||||||
|
"fieldname": "included_in_paid_amount",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Considered In Paid Amount"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-05-25 22:59:38.740883",
|
"links": [],
|
||||||
|
"modified": "2021-06-09 11:48:04.691596",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Taxes and Charges",
|
"name": "Sales Taxes and Charges",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
"sort_order": "ASC"
|
"sort_order": "ASC"
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
|||||||
if not parties:
|
if not parties:
|
||||||
parties.append(party)
|
parties.append(party)
|
||||||
|
|
||||||
fiscal_year = get_fiscal_year(inv.posting_date, company=inv.company)
|
fiscal_year = get_fiscal_year(inv.get('posting_date') or inv.get('transaction_date'), company=inv.company)
|
||||||
tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company)
|
tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company)
|
||||||
|
|
||||||
if not tax_details:
|
if not tax_details:
|
||||||
@@ -154,7 +154,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, p
|
|||||||
tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details)
|
tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details)
|
||||||
|
|
||||||
tax_amount = 0
|
tax_amount = 0
|
||||||
posting_date = inv.posting_date
|
posting_date = inv.get('posting_date') or inv.get('transaction_date')
|
||||||
if party_type == 'Supplier':
|
if party_type == 'Supplier':
|
||||||
ldc = get_lower_deduction_certificate(fiscal_year, pan_no)
|
ldc = get_lower_deduction_certificate(fiscal_year, pan_no)
|
||||||
if tax_deducted:
|
if tax_deducted:
|
||||||
@@ -257,7 +257,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
|
|||||||
if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
|
if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
|
||||||
if ldc and is_valid_certificate(
|
if ldc and is_valid_certificate(
|
||||||
ldc.valid_from, ldc.valid_upto,
|
ldc.valid_from, ldc.valid_upto,
|
||||||
inv.posting_date, tax_deducted,
|
inv.get('posting_date') or inv.get('transaction_date'), tax_deducted,
|
||||||
inv.net_total, ldc.certificate_limit
|
inv.net_total, ldc.certificate_limit
|
||||||
):
|
):
|
||||||
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
|
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
|||||||
si = create_sales_invoice(customer = "Test TCS Customer", rate=5000)
|
si = create_sales_invoice(customer = "Test TCS Customer", rate=5000)
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
tcs_charged = sum([d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC'])
|
tcs_charged = sum(d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC')
|
||||||
self.assertEqual(tcs_charged, 500)
|
self.assertEqual(tcs_charged, 500)
|
||||||
invoices.append(si)
|
invoices.append(si)
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
|
|||||||
validate_expense_against_budget(args)
|
validate_expense_against_budget(args)
|
||||||
|
|
||||||
def validate_cwip_accounts(gl_map):
|
def validate_cwip_accounts(gl_map):
|
||||||
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
|
cwip_enabled = any(cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting"))
|
||||||
|
|
||||||
if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
|
if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
|
||||||
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||||
|
|||||||
@@ -58,11 +58,9 @@ def get_conditions(filters):
|
|||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
|
|
||||||
accounts = frappe.db.get_all("Account", fields=["name", "account_currency"],
|
accounts = frappe.db.get_all("Account", fields=["name", "account_currency"],
|
||||||
filters=conditions)
|
filters=conditions, order_by='name')
|
||||||
|
|
||||||
for d in accounts:
|
for d in accounts:
|
||||||
balance = get_balance_on(d.name, date=filters.report_date)
|
balance = get_balance_on(d.name, date=filters.report_date)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class TestAccountBalance(unittest.TestCase):
|
|||||||
|
|
||||||
expected_data = [
|
expected_data = [
|
||||||
{
|
{
|
||||||
"account": 'Sales - _TC2',
|
"account": 'Direct Income - _TC2',
|
||||||
"currency": 'EUR',
|
"currency": 'EUR',
|
||||||
"balance": -100.0,
|
"balance": -100.0,
|
||||||
},
|
},
|
||||||
@@ -32,21 +32,21 @@ class TestAccountBalance(unittest.TestCase):
|
|||||||
"currency": 'EUR',
|
"currency": 'EUR',
|
||||||
"balance": -100.0,
|
"balance": -100.0,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"account": 'Service - _TC2',
|
|
||||||
"currency": 'EUR',
|
|
||||||
"balance": 0.0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"account": 'Direct Income - _TC2',
|
|
||||||
"currency": 'EUR',
|
|
||||||
"balance": -100.0,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"account": 'Indirect Income - _TC2',
|
"account": 'Indirect Income - _TC2',
|
||||||
"currency": 'EUR',
|
"currency": 'EUR',
|
||||||
"balance": 0.0,
|
"balance": 0.0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"account": 'Sales - _TC2',
|
||||||
|
"currency": 'EUR',
|
||||||
|
"balance": -100.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": 'Service - _TC2',
|
||||||
|
"currency": 'EUR',
|
||||||
|
"balance": 0.0,
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertEqual(expected_data, report[1])
|
self.assertEqual(expected_data, report[1])
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def get_accounts_in_mappers(mapping_names):
|
|||||||
join `tabCash Flow Mapping` cfm on cfma.parent=cfm.name
|
join `tabCash Flow Mapping` cfm on cfma.parent=cfm.name
|
||||||
where cfma.parent in (%s)
|
where cfma.parent in (%s)
|
||||||
order by cfm.is_working_capital
|
order by cfm.is_working_capital
|
||||||
''', (', '.join(['"%s"' % d for d in mapping_names])))
|
''', (', '.join('"%s"' % d for d in mapping_names)))
|
||||||
|
|
||||||
|
|
||||||
def setup_mappers(mappers):
|
def setup_mappers(mappers):
|
||||||
@@ -83,8 +83,8 @@ def setup_mappers(mappers):
|
|||||||
|
|
||||||
account_types_labels = sorted(
|
account_types_labels = sorted(
|
||||||
set(
|
set(
|
||||||
[(d['label'], d['is_working_capital'], d['is_income_tax_liability'], d['is_income_tax_expense'])
|
(d['label'], d['is_working_capital'], d['is_income_tax_liability'], d['is_income_tax_expense'])
|
||||||
for d in account_types]
|
for d in account_types
|
||||||
),
|
),
|
||||||
key=lambda x: x[1]
|
key=lambda x: x[1]
|
||||||
)
|
)
|
||||||
@@ -375,7 +375,7 @@ def _get_account_type_based_data(filters, account_names, period_list, accumulate
|
|||||||
total = 0
|
total = 0
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
start_date = get_start_date(period, accumulated_values, company)
|
start_date = get_start_date(period, accumulated_values, company)
|
||||||
accounts = ', '.join(['"%s"' % d for d in account_names])
|
accounts = ', '.join('"%s"' % d for d in account_names)
|
||||||
|
|
||||||
if opening_balances:
|
if opening_balances:
|
||||||
date_info = dict(date=start_date)
|
date_info = dict(date=start_date)
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class PartyLedgerSummaryReport(object):
|
|||||||
out = []
|
out = []
|
||||||
for party, row in iteritems(self.party_data):
|
for party, row in iteritems(self.party_data):
|
||||||
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
|
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
|
||||||
total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))])
|
total_party_adjustment = sum(amount for amount in itervalues(self.party_adjustment_details.get(party, {})))
|
||||||
row.paid_amount -= total_party_adjustment
|
row.paid_amount -= total_party_adjustment
|
||||||
|
|
||||||
adjustments = self.party_adjustment_details.get(party, {})
|
adjustments = self.party_adjustment_details.get(party, {})
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ def set_gl_entries_by_account(
|
|||||||
|
|
||||||
if accounts:
|
if accounts:
|
||||||
additional_conditions += " and account in ({})"\
|
additional_conditions += " and account in ({})"\
|
||||||
.format(", ".join([frappe.db.escape(d) for d in accounts]))
|
.format(", ".join(frappe.db.escape(d) for d in accounts))
|
||||||
|
|
||||||
gl_filters = {
|
gl_filters = {
|
||||||
"company": company,
|
"company": company,
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ def get_aii_accounts():
|
|||||||
|
|
||||||
def get_purchase_receipts_against_purchase_order(item_list):
|
def get_purchase_receipts_against_purchase_order(item_list):
|
||||||
po_pr_map = frappe._dict()
|
po_pr_map = frappe._dict()
|
||||||
po_item_rows = list(set([d.po_detail for d in item_list]))
|
po_item_rows = list(set(d.po_detail for d in item_list))
|
||||||
|
|
||||||
if po_item_rows:
|
if po_item_rows:
|
||||||
purchase_receipts = frappe.db.sql("""
|
purchase_receipts = frappe.db.sql("""
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
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)
|
||||||
|
|
||||||
mode_of_payments = get_mode_of_payments(set([d.parent for d in item_list]))
|
mode_of_payments = get_mode_of_payments(set(d.parent for d in item_list))
|
||||||
so_dn_map = get_delivery_notes_against_sales_order(item_list)
|
so_dn_map = get_delivery_notes_against_sales_order(item_list)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|||||||
@@ -77,14 +77,14 @@ def get_pos_entries(filters, group_by_field):
|
|||||||
), filters, as_dict=1)
|
), filters, as_dict=1)
|
||||||
|
|
||||||
def concat_mode_of_payments(pos_entries):
|
def concat_mode_of_payments(pos_entries):
|
||||||
mode_of_payments = get_mode_of_payments(set([d.pos_invoice for d in pos_entries]))
|
mode_of_payments = get_mode_of_payments(set(d.pos_invoice for d in pos_entries))
|
||||||
for entry in pos_entries:
|
for entry in pos_entries:
|
||||||
if mode_of_payments.get(entry.pos_invoice):
|
if mode_of_payments.get(entry.pos_invoice):
|
||||||
entry.mode_of_payment = ", ".join(mode_of_payments.get(entry.pos_invoice, []))
|
entry.mode_of_payment = ", ".join(mode_of_payments.get(entry.pos_invoice, []))
|
||||||
|
|
||||||
def add_subtotal_row(data, group_invoices, group_by_field, group_by_value):
|
def add_subtotal_row(data, group_invoices, group_by_field, group_by_value):
|
||||||
grand_total = sum([d.grand_total for d in group_invoices])
|
grand_total = sum(d.grand_total for d in group_invoices)
|
||||||
paid_amount = sum([d.paid_amount for d in group_invoices])
|
paid_amount = sum(d.paid_amount for d in group_invoices)
|
||||||
data.append({
|
data.append({
|
||||||
group_by_field: group_by_value,
|
group_by_field: group_by_value,
|
||||||
"grand_total": grand_total,
|
"grand_total": grand_total,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
|||||||
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
|
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
|
||||||
invoice_expense_map, expense_accounts)
|
invoice_expense_map, expense_accounts)
|
||||||
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
|
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
|
||||||
suppliers = list(set([d.supplier for d in invoice_list]))
|
suppliers = list(set(d.supplier for d in invoice_list))
|
||||||
supplier_details = get_supplier_details(suppliers)
|
supplier_details = get_supplier_details(suppliers)
|
||||||
|
|
||||||
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
||||||
@@ -120,13 +120,13 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
and docstatus = 1 and (account_head is not null and account_head != '')
|
and docstatus = 1 and (account_head is not null and account_head != '')
|
||||||
and category in ('Total', 'Valuation and Total')
|
and category in ('Total', 'Valuation and Total')
|
||||||
and parent in (%s) order by account_head""" %
|
and parent in (%s) order by account_head""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
|
||||||
|
|
||||||
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
|
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
|
||||||
from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
|
from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
|
||||||
and ifnull(unrealized_profit_loss_account, '') != ''
|
and ifnull(unrealized_profit_loss_account, '') != ''
|
||||||
order by unrealized_profit_loss_account""" %
|
order by unrealized_profit_loss_account""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
|
||||||
|
|
||||||
expense_columns = [(account + ":Currency/currency:120") for account in expense_accounts]
|
expense_columns = [(account + ":Currency/currency:120") for account in expense_accounts]
|
||||||
unrealized_profit_loss_account_columns = [(account + ":Currency/currency:120") for account in unrealized_profit_loss_accounts]
|
unrealized_profit_loss_account_columns = [(account + ":Currency/currency:120") for account in unrealized_profit_loss_accounts]
|
||||||
@@ -208,7 +208,7 @@ def get_invoice_expense_map(invoice_list):
|
|||||||
from `tabPurchase Invoice Item`
|
from `tabPurchase Invoice Item`
|
||||||
where parent in (%s)
|
where parent in (%s)
|
||||||
group by parent, expense_account
|
group by parent, expense_account
|
||||||
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
""" % ', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_expense_map = {}
|
invoice_expense_map = {}
|
||||||
for d in expense_details:
|
for d in expense_details:
|
||||||
@@ -221,7 +221,7 @@ def get_internal_invoice_map(invoice_list):
|
|||||||
unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
|
unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
|
||||||
base_net_total as amount from `tabPurchase Invoice` where name in (%s)
|
base_net_total as amount from `tabPurchase Invoice` where name in (%s)
|
||||||
and is_internal_supplier = 1 and company = represents_company""" %
|
and is_internal_supplier = 1 and company = represents_company""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
internal_invoice_map = {}
|
internal_invoice_map = {}
|
||||||
for d in unrealized_amount_details:
|
for d in unrealized_amount_details:
|
||||||
@@ -238,7 +238,7 @@ def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
|
|||||||
where parent in (%s) and category in ('Total', 'Valuation and Total')
|
where parent in (%s) and category in ('Total', 'Valuation and Total')
|
||||||
and base_tax_amount_after_discount_amount != 0
|
and base_tax_amount_after_discount_amount != 0
|
||||||
group by parent, account_head, add_deduct_tax
|
group by parent, account_head, add_deduct_tax
|
||||||
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
""" % ', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_tax_map = {}
|
invoice_tax_map = {}
|
||||||
for d in tax_details:
|
for d in tax_details:
|
||||||
@@ -258,7 +258,7 @@ def get_invoice_po_pr_map(invoice_list):
|
|||||||
select parent, purchase_order, purchase_receipt, po_detail, project
|
select parent, purchase_order, purchase_receipt, po_detail, project
|
||||||
from `tabPurchase Invoice Item`
|
from `tabPurchase Invoice Item`
|
||||||
where parent in (%s)
|
where parent in (%s)
|
||||||
""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
""" % ', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_po_pr_map = {}
|
invoice_po_pr_map = {}
|
||||||
for d in pi_items:
|
for d in pi_items:
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ def get_sales_invoice_data(filters):
|
|||||||
def get_mode_of_payments(filters):
|
def get_mode_of_payments(filters):
|
||||||
mode_of_payments = {}
|
mode_of_payments = {}
|
||||||
invoice_list = get_invoices(filters)
|
invoice_list = get_invoices(filters)
|
||||||
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
|
invoice_list_names = ",".join('"' + invoice['name'] + '"' for invoice in invoice_list)
|
||||||
if invoice_list:
|
if invoice_list:
|
||||||
inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
|
inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
|
||||||
from `tabSales Invoice` a, `tabSales Invoice Payment` b
|
from `tabSales Invoice` a, `tabSales Invoice Payment` b
|
||||||
@@ -197,7 +197,7 @@ def get_invoices(filters):
|
|||||||
def get_mode_of_payment_details(filters):
|
def get_mode_of_payment_details(filters):
|
||||||
mode_of_payment_details = {}
|
mode_of_payment_details = {}
|
||||||
invoice_list = get_invoices(filters)
|
invoice_list = get_invoices(filters)
|
||||||
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
|
invoice_list_names = ",".join('"' + invoice['name'] + '"' for invoice in invoice_list)
|
||||||
if invoice_list:
|
if invoice_list:
|
||||||
inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date,
|
inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date,
|
||||||
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount
|
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount
|
||||||
|
|||||||
@@ -248,19 +248,19 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
income_accounts = frappe.db.sql_list("""select distinct income_account
|
income_accounts = frappe.db.sql_list("""select distinct income_account
|
||||||
from `tabSales Invoice Item` where docstatus = 1 and parent in (%s)
|
from `tabSales Invoice Item` where docstatus = 1 and parent in (%s)
|
||||||
order by income_account""" %
|
order by income_account""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
|
||||||
|
|
||||||
tax_accounts = frappe.db.sql_list("""select distinct account_head
|
tax_accounts = frappe.db.sql_list("""select distinct account_head
|
||||||
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
|
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
|
||||||
and docstatus = 1 and base_tax_amount_after_discount_amount != 0
|
and docstatus = 1 and base_tax_amount_after_discount_amount != 0
|
||||||
and parent in (%s) order by account_head""" %
|
and parent in (%s) order by account_head""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
|
||||||
|
|
||||||
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
|
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
|
||||||
from `tabSales Invoice` where docstatus = 1 and name in (%s)
|
from `tabSales Invoice` where docstatus = 1 and name in (%s)
|
||||||
and ifnull(unrealized_profit_loss_account, '') != ''
|
and ifnull(unrealized_profit_loss_account, '') != ''
|
||||||
order by unrealized_profit_loss_account""" %
|
order by unrealized_profit_loss_account""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
|
||||||
|
|
||||||
for account in income_accounts:
|
for account in income_accounts:
|
||||||
income_columns.append({
|
income_columns.append({
|
||||||
@@ -406,7 +406,7 @@ def get_invoices(filters, additional_query_columns):
|
|||||||
def get_invoice_income_map(invoice_list):
|
def get_invoice_income_map(invoice_list):
|
||||||
income_details = frappe.db.sql("""select parent, income_account, sum(base_net_amount) as amount
|
income_details = frappe.db.sql("""select parent, income_account, sum(base_net_amount) as amount
|
||||||
from `tabSales Invoice Item` where parent in (%s) group by parent, income_account""" %
|
from `tabSales Invoice Item` where parent in (%s) group by parent, income_account""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_income_map = {}
|
invoice_income_map = {}
|
||||||
for d in income_details:
|
for d in income_details:
|
||||||
@@ -419,7 +419,7 @@ def get_internal_invoice_map(invoice_list):
|
|||||||
unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
|
unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
|
||||||
base_net_total as amount from `tabSales Invoice` where name in (%s)
|
base_net_total as amount from `tabSales Invoice` where name in (%s)
|
||||||
and is_internal_customer = 1 and company = represents_company""" %
|
and is_internal_customer = 1 and company = represents_company""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
internal_invoice_map = {}
|
internal_invoice_map = {}
|
||||||
for d in unrealized_amount_details:
|
for d in unrealized_amount_details:
|
||||||
@@ -432,7 +432,7 @@ def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts):
|
|||||||
tax_details = frappe.db.sql("""select parent, account_head,
|
tax_details = frappe.db.sql("""select parent, account_head,
|
||||||
sum(base_tax_amount_after_discount_amount) as tax_amount
|
sum(base_tax_amount_after_discount_amount) as tax_amount
|
||||||
from `tabSales Taxes and Charges` where parent in (%s) group by parent, account_head""" %
|
from `tabSales Taxes and Charges` where parent in (%s) group by parent, account_head""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_tax_map = {}
|
invoice_tax_map = {}
|
||||||
for d in tax_details:
|
for d in tax_details:
|
||||||
@@ -451,7 +451,7 @@ def get_invoice_so_dn_map(invoice_list):
|
|||||||
si_items = frappe.db.sql("""select parent, sales_order, delivery_note, so_detail
|
si_items = frappe.db.sql("""select parent, sales_order, delivery_note, so_detail
|
||||||
from `tabSales Invoice Item` where parent in (%s)
|
from `tabSales Invoice Item` where parent in (%s)
|
||||||
and (ifnull(sales_order, '') != '' or ifnull(delivery_note, '') != '')""" %
|
and (ifnull(sales_order, '') != '' or ifnull(delivery_note, '') != '')""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_so_dn_map = {}
|
invoice_so_dn_map = {}
|
||||||
for d in si_items:
|
for d in si_items:
|
||||||
@@ -475,7 +475,7 @@ def get_invoice_cc_wh_map(invoice_list):
|
|||||||
si_items = frappe.db.sql("""select parent, cost_center, warehouse
|
si_items = frappe.db.sql("""select parent, cost_center, warehouse
|
||||||
from `tabSales Invoice Item` where parent in (%s)
|
from `tabSales Invoice Item` where parent in (%s)
|
||||||
and (ifnull(cost_center, '') != '' or ifnull(warehouse, '') != '')""" %
|
and (ifnull(cost_center, '') != '' or ifnull(warehouse, '') != '')""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
|
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list), as_dict=1)
|
||||||
|
|
||||||
invoice_cc_wh_map = {}
|
invoice_cc_wh_map = {}
|
||||||
for d in si_items:
|
for d in si_items:
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date, f
|
|||||||
and company=%s and posting_date between %s and %s
|
and company=%s and posting_date between %s and %s
|
||||||
""", (supplier, company, from_date, to_date), as_dict=1)
|
""", (supplier, company, from_date, to_date), as_dict=1)
|
||||||
|
|
||||||
supplier_credit_amount = flt(sum([d.credit for d in entries]))
|
supplier_credit_amount = flt(sum(d.credit for d in entries))
|
||||||
|
|
||||||
vouchers = [d.voucher_no for d in entries]
|
vouchers = [d.voucher_no for d in entries]
|
||||||
vouchers += get_advance_vouchers([supplier], company=company,
|
vouchers += get_advance_vouchers([supplier], company=company,
|
||||||
@@ -91,7 +91,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date, f
|
|||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where account=%s and posting_date between %s and %s
|
where account=%s and posting_date between %s and %s
|
||||||
and company=%s and credit > 0 and voucher_no in ({0})
|
and company=%s and credit > 0 and voucher_no in ({0})
|
||||||
""".format(', '.join(["'%s'" % d for d in vouchers])),
|
""".format(', '.join("'%s'" % d for d in vouchers)),
|
||||||
(account, from_date, to_date, company))[0][0])
|
(account, from_date, to_date, company))[0][0])
|
||||||
|
|
||||||
date_range_filter = [fiscal_year, from_date, to_date]
|
date_range_filter = [fiscal_year, from_date, to_date]
|
||||||
|
|||||||
@@ -54,6 +54,32 @@ frappe.query_reports["TDS Payable Monthly"] = {
|
|||||||
frappe.query_report.refresh();
|
frappe.query_report.refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"purchase_order",
|
||||||
|
"label": __("Purchase Order"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Purchase Order",
|
||||||
|
"get_query": function() {
|
||||||
|
return {
|
||||||
|
"filters": {
|
||||||
|
"name": ["in", frappe.query_report.invoices]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on_change: function() {
|
||||||
|
let supplier = frappe.query_report.get_filter_value('supplier');
|
||||||
|
if(!supplier) return; // return if no supplier selected
|
||||||
|
|
||||||
|
// filter invoices based on selected supplier
|
||||||
|
let invoices = [];
|
||||||
|
frappe.query_report.invoice_data.map(d => {
|
||||||
|
if(d.supplier==supplier)
|
||||||
|
invoices.push(d.name)
|
||||||
|
});
|
||||||
|
frappe.query_report.invoices = invoices;
|
||||||
|
frappe.query_report.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"from_date",
|
"fieldname":"from_date",
|
||||||
"label": __("From Date"),
|
"label": __("From Date"),
|
||||||
@@ -75,15 +101,17 @@ frappe.query_reports["TDS Payable Monthly"] = {
|
|||||||
onload: function(report) {
|
onload: function(report) {
|
||||||
// fetch all tds applied invoices
|
// fetch all tds applied invoices
|
||||||
frappe.call({
|
frappe.call({
|
||||||
"method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices",
|
"method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices_and_orders",
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
let invoices = [];
|
let invoices = [];
|
||||||
|
|
||||||
r.message.map(d => {
|
r.message.map(d => {
|
||||||
invoices.push(d.name);
|
invoices.push(d.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
report["invoice_data"] = r.message;
|
report["invoice_data"] = r.message.invoices;
|
||||||
report["invoices"] = invoices;
|
report["invoices"] = invoices;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,14 @@ def execute(filters=None):
|
|||||||
validate_filters(filters)
|
validate_filters(filters)
|
||||||
set_filters(filters)
|
set_filters(filters)
|
||||||
|
|
||||||
|
# TDS payment entries
|
||||||
|
payment_entries = get_payment_entires(filters)
|
||||||
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
if not filters["invoices"]:
|
if not filters.get("invoices"):
|
||||||
return columns, []
|
return columns, []
|
||||||
|
|
||||||
res = get_result(filters)
|
res = get_result(filters, payment_entries)
|
||||||
|
|
||||||
return columns, res
|
return columns, res
|
||||||
|
|
||||||
@@ -27,8 +30,9 @@ def validate_filters(filters):
|
|||||||
def set_filters(filters):
|
def set_filters(filters):
|
||||||
invoices = []
|
invoices = []
|
||||||
|
|
||||||
if not filters["invoices"]:
|
if not filters.get("invoices"):
|
||||||
filters["invoices"] = get_tds_invoices()
|
filters["invoices"] = get_tds_invoices_and_orders()
|
||||||
|
|
||||||
if filters.supplier and filters.purchase_invoice:
|
if filters.supplier and filters.purchase_invoice:
|
||||||
for d in filters["invoices"]:
|
for d in filters["invoices"]:
|
||||||
if d.name == filters.purchase_invoice and d.supplier == filters.supplier:
|
if d.name == filters.purchase_invoice and d.supplier == filters.supplier:
|
||||||
@@ -41,13 +45,29 @@ def set_filters(filters):
|
|||||||
for d in filters["invoices"]:
|
for d in filters["invoices"]:
|
||||||
if d.name == filters.purchase_invoice:
|
if d.name == filters.purchase_invoice:
|
||||||
invoices.append(d)
|
invoices.append(d)
|
||||||
|
elif filters.supplier and filters.purchase_order:
|
||||||
|
for d in filters.get("invoices"):
|
||||||
|
if d.name == filters.purchase_order and d.supplier == filters.supplier:
|
||||||
|
invoices.append(d)
|
||||||
|
elif filters.supplier and not filters.purchase_order:
|
||||||
|
for d in filters.get("invoices"):
|
||||||
|
if d.supplier == filters.supplier:
|
||||||
|
invoices.append(d)
|
||||||
|
elif filters.purchase_order and not filters.supplier:
|
||||||
|
for d in filters.get("invoices"):
|
||||||
|
if d.name == filters.purchase_order:
|
||||||
|
invoices.append(d)
|
||||||
|
|
||||||
filters["invoices"] = invoices if invoices else filters["invoices"]
|
filters["invoices"] = invoices if invoices else filters["invoices"]
|
||||||
filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
|
filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name')
|
||||||
|
|
||||||
def get_result(filters):
|
#print(filters.get('invoices'))
|
||||||
supplier_map, tds_docs = get_supplier_map(filters)
|
|
||||||
gle_map = get_gle_map(filters)
|
def get_result(filters, payment_entries):
|
||||||
|
supplier_map, tds_docs = get_supplier_map(filters, payment_entries)
|
||||||
|
documents = [d.get('name') for d in filters.get('invoices')] + [d.get('name') for d in payment_entries]
|
||||||
|
|
||||||
|
gle_map = get_gle_map(filters, documents)
|
||||||
|
|
||||||
out = []
|
out = []
|
||||||
for d in gle_map:
|
for d in gle_map:
|
||||||
@@ -62,10 +82,11 @@ def get_result(filters):
|
|||||||
|
|
||||||
for k in gle_map[d]:
|
for k in gle_map[d]:
|
||||||
if k.party == supplier_map[d] and k.credit > 0:
|
if k.party == supplier_map[d] and k.credit > 0:
|
||||||
total_amount_credited += k.credit
|
total_amount_credited += (k.credit - k.debit)
|
||||||
elif account_list and k.account == account and k.credit > 0:
|
elif account_list and k.account == account and (k.credit - k.debit) > 0:
|
||||||
tds_deducted = k.credit
|
tds_deducted = (k.credit - k.debit)
|
||||||
total_amount_credited += k.credit
|
total_amount_credited += (k.credit - k.debit)
|
||||||
|
voucher_type = k.voucher_type
|
||||||
|
|
||||||
rate = [i.tax_withholding_rate for i in tds_doc.rates
|
rate = [i.tax_withholding_rate for i in tds_doc.rates
|
||||||
if i.fiscal_year == gle_map[d][0].fiscal_year]
|
if i.fiscal_year == gle_map[d][0].fiscal_year]
|
||||||
@@ -73,32 +94,36 @@ def get_result(filters):
|
|||||||
if rate and len(rate) > 0 and tds_deducted:
|
if rate and len(rate) > 0 and tds_deducted:
|
||||||
rate = rate[0]
|
rate = rate[0]
|
||||||
|
|
||||||
if getdate(filters.from_date) <= gle_map[d][0].posting_date \
|
row = [supplier.pan, supplier.name]
|
||||||
and getdate(filters.to_date) >= gle_map[d][0].posting_date:
|
|
||||||
row = [supplier.pan, supplier.name]
|
|
||||||
|
|
||||||
if filters.naming_series == 'Naming Series':
|
if filters.naming_series == 'Naming Series':
|
||||||
row.append(supplier.supplier_name)
|
row.append(supplier.supplier_name)
|
||||||
|
|
||||||
row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited,
|
row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited,
|
||||||
tds_deducted, gle_map[d][0].posting_date, "Purchase Invoice", d])
|
tds_deducted, gle_map[d][0].posting_date, voucher_type, d])
|
||||||
out.append(row)
|
out.append(row)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_supplier_map(filters):
|
def get_supplier_map(filters, payment_entries):
|
||||||
# create a supplier_map of the form {"purchase_invoice": {supplier_name, pan, tds_name}}
|
# create a supplier_map of the form {"purchase_invoice": {supplier_name, pan, tds_name}}
|
||||||
# pre-fetch all distinct applicable tds docs
|
# pre-fetch all distinct applicable tds docs
|
||||||
supplier_map, tds_docs = {}, {}
|
supplier_map, tds_docs = {}, {}
|
||||||
pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
|
pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
|
||||||
|
supplier_list = [d.supplier for d in filters["invoices"]]
|
||||||
|
|
||||||
supplier_detail = frappe.db.get_all('Supplier',
|
supplier_detail = frappe.db.get_all('Supplier',
|
||||||
{"name": ["in", [d.supplier for d in filters["invoices"]]]},
|
{"name": ["in", supplier_list]},
|
||||||
["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"])
|
["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"])
|
||||||
|
|
||||||
for d in filters["invoices"]:
|
for d in filters["invoices"]:
|
||||||
supplier_map[d.get("name")] = [k for k in supplier_detail
|
supplier_map[d.get("name")] = [k for k in supplier_detail
|
||||||
if k.name == d.get("supplier")][0]
|
if k.name == d.get("supplier")][0]
|
||||||
|
|
||||||
|
for d in payment_entries:
|
||||||
|
supplier_map[d.get("name")] = [k for k in supplier_detail
|
||||||
|
if k.name == d.get("supplier")][0]
|
||||||
|
|
||||||
for d in supplier_detail:
|
for d in supplier_detail:
|
||||||
if d.get("tax_withholding_category") not in tds_docs:
|
if d.get("tax_withholding_category") not in tds_docs:
|
||||||
tds_docs[d.get("tax_withholding_category")] = \
|
tds_docs[d.get("tax_withholding_category")] = \
|
||||||
@@ -106,13 +131,19 @@ def get_supplier_map(filters):
|
|||||||
|
|
||||||
return supplier_map, tds_docs
|
return supplier_map, tds_docs
|
||||||
|
|
||||||
def get_gle_map(filters):
|
def get_gle_map(filters, documents):
|
||||||
# create gle_map of the form
|
# create gle_map of the form
|
||||||
# {"purchase_invoice": list of dict of all gle created for this invoice}
|
# {"purchase_invoice": list of dict of all gle created for this invoice}
|
||||||
gle_map = {}
|
gle_map = {}
|
||||||
gle = frappe.db.get_all('GL Entry',\
|
|
||||||
{"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]], 'is_cancelled': 0},
|
gle = frappe.db.get_all('GL Entry',
|
||||||
["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date"])
|
{
|
||||||
|
"voucher_no": ["in", documents],
|
||||||
|
'is_cancelled': 0,
|
||||||
|
'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]),
|
||||||
|
},
|
||||||
|
["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date", "voucher_type"],
|
||||||
|
)
|
||||||
|
|
||||||
for d in gle:
|
for d in gle:
|
||||||
if not d.voucher_no in gle_map:
|
if not d.voucher_no in gle_map:
|
||||||
@@ -201,8 +232,26 @@ def get_columns(filters):
|
|||||||
|
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
|
def get_payment_entires(filters):
|
||||||
|
filter_dict = {
|
||||||
|
'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]),
|
||||||
|
'party_type': 'Supplier',
|
||||||
|
'apply_tax_withholding_amount': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters.get('purchase_invoice') or filters.get('purchase_order'):
|
||||||
|
parent = frappe.db.get_all('Payment Entry Reference',
|
||||||
|
{'reference_name': ('in', [d.get('name') for d in filters.get('invoices')])}, ['parent'])
|
||||||
|
|
||||||
|
filter_dict.update({'name': ('in', [d.get('parent') for d in parent])})
|
||||||
|
|
||||||
|
payment_entries = frappe.get_all('Payment Entry', fields=['name', 'party_name as supplier'],
|
||||||
|
filters=filter_dict)
|
||||||
|
|
||||||
|
return payment_entries
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_tds_invoices():
|
def get_tds_invoices_and_orders():
|
||||||
# fetch tds applicable supplier and fetch invoices for these suppliers
|
# fetch tds applicable supplier and fetch invoices for these suppliers
|
||||||
suppliers = [d.name for d in frappe.db.get_list("Supplier",
|
suppliers = [d.name for d in frappe.db.get_list("Supplier",
|
||||||
{"tax_withholding_category": ["!=", ""]}, ["name"])]
|
{"tax_withholding_category": ["!=", ""]}, ["name"])]
|
||||||
@@ -210,7 +259,12 @@ def get_tds_invoices():
|
|||||||
invoices = frappe.db.get_list("Purchase Invoice",
|
invoices = frappe.db.get_list("Purchase Invoice",
|
||||||
{"supplier": ["in", suppliers]}, ["name", "supplier"])
|
{"supplier": ["in", suppliers]}, ["name", "supplier"])
|
||||||
|
|
||||||
|
orders = frappe.db.get_list("Purchase Order",
|
||||||
|
{"supplier": ["in", suppliers]}, ["name", "supplier"])
|
||||||
|
|
||||||
|
invoices = invoices + orders
|
||||||
invoices = [d for d in invoices if d.supplier]
|
invoices = [d for d in invoices if d.supplier]
|
||||||
|
|
||||||
frappe.cache().hset("invoices", frappe.session.user, invoices)
|
frappe.cache().hset("invoices", frappe.session.user, invoices)
|
||||||
|
|
||||||
return invoices
|
return invoices
|
||||||
|
|||||||
@@ -139,6 +139,6 @@ def get_invoiced_item_gross_margin(sales_invoice=None, item_code=None, company=N
|
|||||||
gross_profit_data = GrossProfitGenerator(filters)
|
gross_profit_data = GrossProfitGenerator(filters)
|
||||||
result = gross_profit_data.grouped_data
|
result = gross_profit_data.grouped_data
|
||||||
if not with_item_data:
|
if not with_item_data:
|
||||||
result = sum([d.gross_profit for d in result])
|
result = sum(d.gross_profit for d in result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -635,7 +635,7 @@ def get_held_invoices(party_type, party):
|
|||||||
'select name from `tabPurchase Invoice` where release_date IS NOT NULL and release_date > CURDATE()',
|
'select name from `tabPurchase Invoice` where release_date IS NOT NULL and release_date > CURDATE()',
|
||||||
as_dict=1
|
as_dict=1
|
||||||
)
|
)
|
||||||
held_invoices = set([d['name'] for d in held_invoices])
|
held_invoices = set(d['name'] for d in held_invoices)
|
||||||
|
|
||||||
return held_invoices
|
return held_invoices
|
||||||
|
|
||||||
|
|||||||
@@ -445,15 +445,15 @@
|
|||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dependencies": "GL Entry",
|
"dependencies": "GL Entry",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 1,
|
"is_query_report": 1,
|
||||||
"label": "UAE VAT 201",
|
"label": "UAE VAT 201",
|
||||||
"link_to": "UAE VAT 201",
|
"link_to": "UAE VAT 201",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
@@ -684,6 +684,7 @@
|
|||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
"label": "Goods and Services Tax (GST India)",
|
"label": "Goods and Services Tax (GST India)",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Card Break"
|
"type": "Card Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -694,6 +695,7 @@
|
|||||||
"link_to": "GST Settings",
|
"link_to": "GST Settings",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -704,6 +706,7 @@
|
|||||||
"link_to": "GST HSN Code",
|
"link_to": "GST HSN Code",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -714,6 +717,7 @@
|
|||||||
"link_to": "GSTR-1",
|
"link_to": "GSTR-1",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -724,6 +728,7 @@
|
|||||||
"link_to": "GSTR-2",
|
"link_to": "GSTR-2",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -734,6 +739,7 @@
|
|||||||
"link_to": "GSTR 3B Report",
|
"link_to": "GSTR 3B Report",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -744,6 +750,7 @@
|
|||||||
"link_to": "GST Sales Register",
|
"link_to": "GST Sales Register",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -754,6 +761,7 @@
|
|||||||
"link_to": "GST Purchase Register",
|
"link_to": "GST Purchase Register",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -764,6 +772,7 @@
|
|||||||
"link_to": "GST Itemised Sales Register",
|
"link_to": "GST Itemised Sales Register",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -774,6 +783,7 @@
|
|||||||
"link_to": "GST Itemised Purchase Register",
|
"link_to": "GST Itemised Purchase Register",
|
||||||
"link_type": "Report",
|
"link_type": "Report",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -784,6 +794,7 @@
|
|||||||
"link_to": "C-Form",
|
"link_to": "C-Form",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -794,6 +805,7 @@
|
|||||||
"link_to": "Lower Deduction Certificate",
|
"link_to": "Lower Deduction Certificate",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
|
"only_for": "India",
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1052,7 +1064,7 @@
|
|||||||
"type": "Link"
|
"type": "Link"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-05-12 11:48:01.905144",
|
"modified": "2021-06-10 03:17:31.427945",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Accounting",
|
"name": "Accounting",
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
})
|
})
|
||||||
asset.insert()
|
asset.insert()
|
||||||
accumulated_depreciation_after_full_schedule = \
|
accumulated_depreciation_after_full_schedule = \
|
||||||
max([d.accumulated_depreciation_amount for d in asset.get("schedules")])
|
max(d.accumulated_depreciation_amount for d in asset.get("schedules"))
|
||||||
|
|
||||||
asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) -
|
asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) -
|
||||||
flt(accumulated_depreciation_after_full_schedule))
|
flt(accumulated_depreciation_after_full_schedule))
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class AssetValueAdjustment(Document):
|
|||||||
d.value_after_depreciation = asset_value
|
d.value_after_depreciation = asset_value
|
||||||
|
|
||||||
if d.depreciation_method in ("Straight Line", "Manual"):
|
if d.depreciation_method in ("Straight Line", "Manual"):
|
||||||
end_date = max([s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx])
|
end_date = max(s.schedule_date for s in asset.schedules if cint(s.finance_book_id) == d.idx)
|
||||||
total_days = date_diff(end_date, self.date)
|
total_days = date_diff(end_date, self.date)
|
||||||
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
|
rate_per_day = flt(d.value_after_depreciation) / flt(total_days)
|
||||||
from_date = self.date
|
from_date = self.date
|
||||||
|
|||||||
@@ -45,6 +45,14 @@ frappe.ui.form.on("Purchase Order", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
|
},
|
||||||
|
|
||||||
|
apply_tds: function(frm) {
|
||||||
|
if (!frm.doc.apply_tds) {
|
||||||
|
frm.set_value("tax_withholding_category", '');
|
||||||
|
} else {
|
||||||
|
frm.set_value("tax_withholding_category", frm.supplier_tds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -313,7 +321,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
if(me.values) {
|
if(me.values) {
|
||||||
me.values.sub_con_rm_items.map((row,i) => {
|
me.values.sub_con_rm_items.map((row,i) => {
|
||||||
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
|
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
|
||||||
frappe.throw(__("Item Code, warehouse, quantity are required on row {0}", [i+1]));
|
let row_id = i+1;
|
||||||
|
frappe.throw(__("Item Code, warehouse and quantity are required on row {0}", [row_id]));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
|
me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
|
||||||
@@ -509,7 +518,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
args: {
|
args: {
|
||||||
reference_doctype: me.frm.doctype,
|
reference_doctype: me.frm.doctype,
|
||||||
reference_name: me.frm.docname,
|
reference_name: me.frm.docname,
|
||||||
content: __('Reason for hold: ')+data.reason_for_hold,
|
content: __('Reason for hold:') + " " +data.reason_for_hold,
|
||||||
comment_email: frappe.session.user,
|
comment_email: frappe.session.user,
|
||||||
comment_by: frappe.session.user_fullname
|
comment_by: frappe.session.user_fullname
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@ from erpnext.accounts.party import get_party_account_currency
|
|||||||
from six import string_types
|
from six import string_types
|
||||||
from erpnext.stock.doctype.item.item import get_item_defaults
|
from erpnext.stock.doctype.item.item import get_item_defaults
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||||
|
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
||||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
|
||||||
unlink_inter_company_doc
|
unlink_inter_company_doc
|
||||||
|
|
||||||
@@ -39,11 +40,18 @@ class PurchaseOrder(BuyingController):
|
|||||||
'percent_join_field': 'material_request'
|
'percent_join_field': 'material_request'
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
def onload(self):
|
||||||
|
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
|
||||||
|
self.set_onload("supplier_tds", supplier_tds)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(PurchaseOrder, self).validate()
|
super(PurchaseOrder, self).validate()
|
||||||
|
|
||||||
self.set_status()
|
self.set_status()
|
||||||
|
|
||||||
|
# apply tax withholding only if checked and applicable
|
||||||
|
self.set_tax_withholding()
|
||||||
|
|
||||||
self.validate_supplier()
|
self.validate_supplier()
|
||||||
self.validate_schedule_date()
|
self.validate_schedule_date()
|
||||||
validate_for_items(self)
|
validate_for_items(self)
|
||||||
@@ -87,6 +95,33 @@ class PurchaseOrder(BuyingController):
|
|||||||
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
||||||
self.validate_rate_with_reference_doc([["Supplier Quotation", "supplier_quotation", "supplier_quotation_item"]])
|
self.validate_rate_with_reference_doc([["Supplier Quotation", "supplier_quotation", "supplier_quotation_item"]])
|
||||||
|
|
||||||
|
def set_tax_withholding(self):
|
||||||
|
if not self.apply_tds:
|
||||||
|
return
|
||||||
|
|
||||||
|
tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
|
||||||
|
|
||||||
|
if not tax_withholding_details:
|
||||||
|
return
|
||||||
|
|
||||||
|
accounts = []
|
||||||
|
for d in self.taxes:
|
||||||
|
if d.account_head == tax_withholding_details.get("account_head"):
|
||||||
|
d.update(tax_withholding_details)
|
||||||
|
accounts.append(d.account_head)
|
||||||
|
|
||||||
|
if not accounts or tax_withholding_details.get("account_head") not in accounts:
|
||||||
|
self.append("taxes", tax_withholding_details)
|
||||||
|
|
||||||
|
to_remove = [d for d in self.taxes
|
||||||
|
if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
|
||||||
|
|
||||||
|
for d in to_remove:
|
||||||
|
self.remove(d)
|
||||||
|
|
||||||
|
# calculate totals again after applying TDS
|
||||||
|
self.calculate_taxes_and_totals()
|
||||||
|
|
||||||
def validate_supplier(self):
|
def validate_supplier(self):
|
||||||
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
|
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
|
||||||
if prevent_po:
|
if prevent_po:
|
||||||
@@ -104,7 +139,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
|
|
||||||
def validate_minimum_order_qty(self):
|
def validate_minimum_order_qty(self):
|
||||||
if not self.get("items"): return
|
if not self.get("items"): return
|
||||||
items = list(set([d.item_code for d in self.get("items")]))
|
items = list(set(d.item_code for d in self.get("items")))
|
||||||
|
|
||||||
itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty
|
itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty
|
||||||
from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
|
from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
|
||||||
@@ -291,10 +326,10 @@ class PurchaseOrder(BuyingController):
|
|||||||
so.notify_update()
|
so.notify_update()
|
||||||
|
|
||||||
def has_drop_ship_item(self):
|
def has_drop_ship_item(self):
|
||||||
return any([d.delivered_by_supplier for d in self.items])
|
return any(d.delivered_by_supplier for d in self.items)
|
||||||
|
|
||||||
def is_against_so(self):
|
def is_against_so(self):
|
||||||
return any([d.sales_order for d in self.items if d.sales_order])
|
return any(d.sales_order for d in self.items if d.sales_order)
|
||||||
|
|
||||||
def set_received_qty_for_drop_ship_items(self):
|
def set_received_qty_for_drop_ship_items(self):
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
po.reload()
|
po.reload()
|
||||||
|
|
||||||
total_reqd_qty_after_change = sum([d.get("required_qty") for d in po.as_dict().get("supplied_items")])
|
total_reqd_qty_after_change = sum(d.get("required_qty") for d in po.as_dict().get("supplied_items"))
|
||||||
|
|
||||||
self.assertEqual(total_reqd_qty_after_change, 2 * total_reqd_qty)
|
self.assertEqual(total_reqd_qty_after_change, 2 * total_reqd_qty)
|
||||||
|
|
||||||
@@ -1111,7 +1111,7 @@ def create_purchase_order(**args):
|
|||||||
|
|
||||||
po.schedule_date = add_days(nowdate(), 1)
|
po.schedule_date = add_days(nowdate(), 1)
|
||||||
po.company = args.company or "_Test Company"
|
po.company = args.company or "_Test Company"
|
||||||
po.supplier = args.customer or "_Test Supplier"
|
po.supplier = args.supplier or "_Test Supplier"
|
||||||
po.is_subcontracted = args.is_subcontracted or "No"
|
po.is_subcontracted = args.is_subcontracted or "No"
|
||||||
po.currency = args.currency or frappe.get_cached_value('Company', po.company, "default_currency")
|
po.currency = args.currency or frappe.get_cached_value('Company', po.company, "default_currency")
|
||||||
po.conversion_factor = args.conversion_factor or 1
|
po.conversion_factor = args.conversion_factor or 1
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ def get_item_from_material_requests_based_on_supplier(source_name, target_doc =
|
|||||||
def get_supplier_tag():
|
def get_supplier_tag():
|
||||||
if not frappe.cache().hget("Supplier", "Tags"):
|
if not frappe.cache().hget("Supplier", "Tags"):
|
||||||
filters = {"document_type": "Supplier"}
|
filters = {"document_type": "Supplier"}
|
||||||
tags = list(set([tag.tag for tag in frappe.get_all("Tag Link", filters=filters, fields=["tag"]) if tag]))
|
tags = list(set(tag.tag for tag in frappe.get_all("Tag Link", filters=filters, fields=["tag"]) if tag))
|
||||||
frappe.cache().hset("Supplier", "Tags", tags)
|
frappe.cache().hset("Supplier", "Tags", tags)
|
||||||
|
|
||||||
return frappe.cache().hget("Supplier", "Tags")
|
return frappe.cache().hget("Supplier", "Tags")
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ def execute(filters=None):
|
|||||||
if filters.from_date >= filters.to_date:
|
if filters.from_date >= filters.to_date:
|
||||||
frappe.msgprint(_("To Date must be greater than From Date"))
|
frappe.msgprint(_("To Date must be greater than From Date"))
|
||||||
|
|
||||||
data = []
|
|
||||||
columns = get_columns()
|
columns = get_columns()
|
||||||
get_data(data , filters)
|
data = get_data(filters)
|
||||||
return columns, data
|
|
||||||
|
return columns, data or []
|
||||||
|
|
||||||
def get_columns():
|
def get_columns():
|
||||||
return [
|
return [
|
||||||
@@ -21,13 +21,12 @@ def get_columns():
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"fieldname": "purchase_order",
|
"fieldname": "purchase_order",
|
||||||
"options": "Purchase Order",
|
"options": "Purchase Order",
|
||||||
"width": 150
|
"width": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Date"),
|
"label": _("Date"),
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"fieldname": "date",
|
"fieldname": "date",
|
||||||
"hidden": 1,
|
|
||||||
"width": 150
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -41,97 +40,58 @@ def get_columns():
|
|||||||
"label": _("Item Code"),
|
"label": _("Item Code"),
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"fieldname": "rm_item_code",
|
"fieldname": "rm_item_code",
|
||||||
"width": 100
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Required Quantity"),
|
"label": _("Required Quantity"),
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"fieldname": "r_qty",
|
"fieldname": "reqd_qty",
|
||||||
"width": 100
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Transferred Quantity"),
|
"label": _("Transferred Quantity"),
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"fieldname": "t_qty",
|
"fieldname": "transferred_qty",
|
||||||
"width": 100
|
"width": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Pending Quantity"),
|
"label": _("Pending Quantity"),
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"fieldname": "p_qty",
|
"fieldname": "p_qty",
|
||||||
"width": 100
|
"width": 150
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_data(data, filters):
|
def get_data(filters):
|
||||||
po = get_po(filters)
|
po_rm_item_details = get_po_items_to_supply(filters)
|
||||||
po_transferred_qty_map = frappe._dict(get_transferred_quantity([v.name for v in po]))
|
|
||||||
|
|
||||||
sub_items = get_purchase_order_item_supplied([v.name for v in po])
|
data = []
|
||||||
|
for row in po_rm_item_details:
|
||||||
|
transferred_qty = row.get("transferred_qty") or 0
|
||||||
|
if transferred_qty < row.get("reqd_qty", 0):
|
||||||
|
pending_qty = frappe.utils.flt(row.get("reqd_qty", 0) - transferred_qty)
|
||||||
|
row.p_qty = pending_qty if pending_qty > 0 else 0
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
for order in po:
|
return data
|
||||||
for item in sub_items:
|
|
||||||
if order.name == item.parent and order.name in po_transferred_qty_map and \
|
|
||||||
item.required_qty != po_transferred_qty_map.get(order.name).get(item.rm_item_code):
|
|
||||||
transferred_qty = po_transferred_qty_map.get(order.name).get(item.rm_item_code) \
|
|
||||||
if po_transferred_qty_map.get(order.name).get(item.rm_item_code) else 0
|
|
||||||
row ={
|
|
||||||
'purchase_order': item.parent,
|
|
||||||
'date': order.transaction_date,
|
|
||||||
'supplier': order.supplier,
|
|
||||||
'rm_item_code': item.rm_item_code,
|
|
||||||
'r_qty': item.required_qty,
|
|
||||||
't_qty':transferred_qty,
|
|
||||||
'p_qty':item.required_qty - transferred_qty
|
|
||||||
}
|
|
||||||
|
|
||||||
data.append(row)
|
def get_po_items_to_supply(filters):
|
||||||
|
return frappe.db.get_all(
|
||||||
return(data)
|
"Purchase Order",
|
||||||
|
fields=[
|
||||||
def get_po(filters):
|
"name as purchase_order",
|
||||||
record_filters = [
|
"transaction_date as date",
|
||||||
["is_subcontracted", "=", "Yes"],
|
"supplier as supplier",
|
||||||
["supplier", "=", filters.supplier],
|
"`tabPurchase Order Item Supplied`.rm_item_code as rm_item_code",
|
||||||
["transaction_date", "<=", filters.to_date],
|
"`tabPurchase Order Item Supplied`.required_qty as reqd_qty",
|
||||||
["transaction_date", ">=", filters.from_date],
|
"`tabPurchase Order Item Supplied`.supplied_qty as transferred_qty"
|
||||||
["docstatus", "=", 1]
|
|
||||||
]
|
|
||||||
return frappe.get_all("Purchase Order", filters=record_filters, fields=["name", "transaction_date", "supplier"])
|
|
||||||
|
|
||||||
def get_transferred_quantity(po_name):
|
|
||||||
stock_entries = get_stock_entry(po_name)
|
|
||||||
stock_entries_detail = get_stock_entry_detail([v.name for v in stock_entries])
|
|
||||||
po_transferred_qty_map = {}
|
|
||||||
|
|
||||||
|
|
||||||
for entry in stock_entries:
|
|
||||||
for details in stock_entries_detail:
|
|
||||||
if details.parent == entry.name:
|
|
||||||
details["Purchase_order"] = entry.purchase_order
|
|
||||||
if entry.purchase_order not in po_transferred_qty_map:
|
|
||||||
po_transferred_qty_map[entry.purchase_order] = {}
|
|
||||||
po_transferred_qty_map[entry.purchase_order][details.item_code] = details.qty
|
|
||||||
else:
|
|
||||||
po_transferred_qty_map[entry.purchase_order][details.item_code] = po_transferred_qty_map[entry.purchase_order].get(details.item_code, 0) + details.qty
|
|
||||||
|
|
||||||
return po_transferred_qty_map
|
|
||||||
|
|
||||||
|
|
||||||
def get_stock_entry(po):
|
|
||||||
return frappe.get_all("Stock Entry", filters=[
|
|
||||||
('purchase_order', 'IN', po),
|
|
||||||
('stock_entry_type', '=', 'Send to Subcontractor'),
|
|
||||||
('docstatus', '=', 1)
|
|
||||||
], fields=["name", "purchase_order"])
|
|
||||||
|
|
||||||
def get_stock_entry_detail(se):
|
|
||||||
return frappe.get_all("Stock Entry Detail", filters=[
|
|
||||||
["parent", "in", se]
|
|
||||||
],
|
],
|
||||||
fields=["parent", "item_code", "qty"])
|
filters = [
|
||||||
|
["Purchase Order", "per_received", "<", "100"],
|
||||||
def get_purchase_order_item_supplied(po):
|
["Purchase Order", "is_subcontracted", "=", "Yes"],
|
||||||
return frappe.get_all("Purchase Order Item Supplied", filters=[
|
["Purchase Order", "supplier", "=", filters.supplier],
|
||||||
('parent', 'IN', po)
|
["Purchase Order", "transaction_date", "<=", filters.to_date],
|
||||||
], fields=['parent', 'rm_item_code', 'required_qty'])
|
["Purchase Order", "transaction_date", ">=", filters.from_date],
|
||||||
|
["Purchase Order", "docstatus", "=", 1]
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -12,34 +12,68 @@ import json, frappe, unittest
|
|||||||
class TestSubcontractedItemToBeTransferred(unittest.TestCase):
|
class TestSubcontractedItemToBeTransferred(unittest.TestCase):
|
||||||
|
|
||||||
def test_pending_and_transferred_qty(self):
|
def test_pending_and_transferred_qty(self):
|
||||||
po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
|
po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes', supplier_warehouse="_Test Warehouse 1 - _TC")
|
||||||
|
|
||||||
|
# Material Receipt of RMs
|
||||||
make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
|
make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
|
||||||
make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
|
make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
|
||||||
transfer_subcontracted_raw_materials(po.name)
|
|
||||||
col, data = execute(filters=frappe._dict({'supplier': po.supplier,
|
se = transfer_subcontracted_raw_materials(po)
|
||||||
'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
|
|
||||||
'to_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=10))}))
|
col, data = execute(filters=frappe._dict(
|
||||||
self.assertEqual(data[0]['purchase_order'], po.name)
|
{
|
||||||
self.assertIn(data[0]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
|
'supplier': po.supplier,
|
||||||
self.assertIn(data[0]['p_qty'], [9, 18])
|
'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
|
||||||
self.assertIn(data[0]['t_qty'], [1, 2])
|
'to_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=10))
|
||||||
|
}
|
||||||
|
))
|
||||||
|
po.reload()
|
||||||
|
|
||||||
|
po_data = [row for row in data if row.get('purchase_order') == po.name]
|
||||||
|
|
||||||
|
self.assertEqual(len(po_data), 2)
|
||||||
|
self.assertIn(po_data[0]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
|
||||||
|
self.assertIn(po_data[0]['p_qty'], [9, 18])
|
||||||
|
self.assertIn(po_data[0]['transferred_qty'], [1, 2])
|
||||||
|
|
||||||
self.assertEqual(data[1]['purchase_order'], po.name)
|
self.assertEqual(data[1]['purchase_order'], po.name)
|
||||||
self.assertIn(data[1]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
|
self.assertIn(data[1]['rm_item_code'], ['_Test Item', '_Test Item Home Desktop 100'])
|
||||||
self.assertIn(data[1]['p_qty'], [9, 18])
|
self.assertIn(data[1]['p_qty'], [9, 18])
|
||||||
self.assertIn(data[1]['t_qty'], [1, 2])
|
self.assertIn(data[1]['transferred_qty'], [1, 2])
|
||||||
|
|
||||||
|
se.cancel()
|
||||||
|
po.cancel()
|
||||||
|
|
||||||
def transfer_subcontracted_raw_materials(po):
|
def transfer_subcontracted_raw_materials(po):
|
||||||
rm_item = [
|
rm_item = [
|
||||||
{'item_code': '_Test Item', 'rm_item_code': '_Test Item', 'item_name': '_Test Item', 'qty': 1,
|
{
|
||||||
'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 100, 'stock_uom': 'Nos'},
|
'name': po.supplied_items[0].name,
|
||||||
{'item_code': '_Test Item Home Desktop 100', 'rm_item_code': '_Test Item Home Desktop 100', 'item_name': '_Test Item Home Desktop 100', 'qty': 2,
|
'item_code': '_Test Item Home Desktop 100',
|
||||||
'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 200, 'stock_uom': 'Nos'}]
|
'rm_item_code': '_Test Item Home Desktop 100',
|
||||||
|
'item_name': '_Test Item Home Desktop 100',
|
||||||
|
'qty': 2,
|
||||||
|
'warehouse': '_Test Warehouse - _TC',
|
||||||
|
'rate': 100,
|
||||||
|
'amount': 200,
|
||||||
|
'stock_uom': 'Nos'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': po.supplied_items[1].name,
|
||||||
|
'item_code': '_Test Item',
|
||||||
|
'rm_item_code': '_Test Item',
|
||||||
|
'item_name': '_Test Item',
|
||||||
|
'qty': 1,
|
||||||
|
'warehouse': '_Test Warehouse - _TC',
|
||||||
|
'rate': 100,
|
||||||
|
'amount': 100,
|
||||||
|
'stock_uom': 'Nos'
|
||||||
|
}
|
||||||
|
]
|
||||||
rm_item_string = json.dumps(rm_item)
|
rm_item_string = json.dumps(rm_item)
|
||||||
se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string))
|
se = frappe.get_doc(make_rm_stock_entry(po.name, rm_item_string))
|
||||||
se.from_warehouse = '_Test Warehouse 1 - _TC'
|
se.from_warehouse = '_Test Warehouse - _TC'
|
||||||
se.to_warehouse = '_Test Warehouse 1 - _TC'
|
se.to_warehouse = '_Test Warehouse - _TC'
|
||||||
se.stock_entry_type = 'Send to Subcontractor'
|
se.stock_entry_type = 'Send to Subcontractor'
|
||||||
se.save()
|
se.save()
|
||||||
se.submit()
|
se.submit()
|
||||||
|
return se
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
if self.doctype == 'Purchase Invoice':
|
if self.doctype == 'Purchase Invoice':
|
||||||
self.calculate_paid_amount()
|
self.calculate_paid_amount()
|
||||||
|
# apply tax withholding only if checked and applicable
|
||||||
|
self.set_tax_withholding()
|
||||||
|
|
||||||
if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
|
if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
|
||||||
pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
|
pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
|
||||||
@@ -608,8 +610,8 @@ class AccountsController(TransactionBase):
|
|||||||
order_field = "purchase_order"
|
order_field = "purchase_order"
|
||||||
order_doctype = "Purchase Order"
|
order_doctype = "Purchase Order"
|
||||||
|
|
||||||
order_list = list(set([d.get(order_field)
|
order_list = list(set(d.get(order_field)
|
||||||
for d in self.get("items") if d.get(order_field)]))
|
for d in self.get("items") if d.get(order_field)))
|
||||||
|
|
||||||
journal_entries = get_advance_journal_entries(party_type, party, party_account,
|
journal_entries = get_advance_journal_entries(party_type, party, party_account,
|
||||||
amount_field, order_doctype, order_list, include_unallocated)
|
amount_field, order_doctype, order_list, include_unallocated)
|
||||||
@@ -633,8 +635,8 @@ class AccountsController(TransactionBase):
|
|||||||
|
|
||||||
def validate_advance_entries(self):
|
def validate_advance_entries(self):
|
||||||
order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order"
|
order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order"
|
||||||
order_list = list(set([d.get(order_field)
|
order_list = list(set(d.get(order_field)
|
||||||
for d in self.get("items") if d.get(order_field)]))
|
for d in self.get("items") if d.get(order_field)))
|
||||||
|
|
||||||
if not order_list: return
|
if not order_list: return
|
||||||
|
|
||||||
@@ -700,6 +702,7 @@ class AccountsController(TransactionBase):
|
|||||||
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
|
||||||
|
|
||||||
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||||
|
self.update_allocated_advance_taxes_on_cancel()
|
||||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
|
||||||
unlink_ref_doc_from_payment_entries(self)
|
unlink_ref_doc_from_payment_entries(self)
|
||||||
|
|
||||||
@@ -707,6 +710,87 @@ class AccountsController(TransactionBase):
|
|||||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
|
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
|
||||||
unlink_ref_doc_from_payment_entries(self)
|
unlink_ref_doc_from_payment_entries(self)
|
||||||
|
|
||||||
|
def get_tax_map(self):
|
||||||
|
tax_map = {}
|
||||||
|
for tax in self.get('taxes'):
|
||||||
|
tax_map.setdefault(tax.account_head, 0.0)
|
||||||
|
tax_map[tax.account_head] += tax.tax_amount
|
||||||
|
|
||||||
|
return tax_map
|
||||||
|
|
||||||
|
def update_allocated_advance_taxes_on_cancel(self):
|
||||||
|
if self.get('advances'):
|
||||||
|
tax_accounts = [d.account_head for d in self.get('taxes')]
|
||||||
|
allocated_tax_map = frappe._dict(frappe.get_all('GL Entry', fields=['account', 'sum(credit - debit)'],
|
||||||
|
filters={'voucher_no': self.name, 'account': ('in', tax_accounts)},
|
||||||
|
group_by='account', as_list=1))
|
||||||
|
|
||||||
|
tax_map = self.get_tax_map()
|
||||||
|
|
||||||
|
for pe in self.get('advances'):
|
||||||
|
if pe.reference_type == 'Payment Entry':
|
||||||
|
pe = frappe.get_doc('Payment Entry', pe.reference_name)
|
||||||
|
for tax in pe.get('taxes'):
|
||||||
|
allocated_amount = tax_map.get(tax.account_head) - allocated_tax_map.get(tax.account_head)
|
||||||
|
if allocated_amount > tax.tax_amount:
|
||||||
|
allocated_amount = tax.tax_amount
|
||||||
|
|
||||||
|
if allocated_amount:
|
||||||
|
frappe.db.set_value('Advance Taxes and Charges', tax.name, 'allocated_amount',
|
||||||
|
tax.allocated_amount - allocated_amount)
|
||||||
|
tax_map[tax.account_head] -= allocated_amount
|
||||||
|
allocated_tax_map[tax.account_head] -= allocated_amount
|
||||||
|
|
||||||
|
def allocate_advance_taxes(self, gl_entries):
|
||||||
|
tax_map = self.get_tax_map()
|
||||||
|
for pe in self.get("advances"):
|
||||||
|
if pe.reference_type == "Payment Entry" and \
|
||||||
|
frappe.db.get_value('Payment Entry', pe.reference_name, 'advance_tax_account'):
|
||||||
|
pe = frappe.get_doc("Payment Entry", pe.reference_name)
|
||||||
|
for tax in pe.get("taxes"):
|
||||||
|
account_currency = get_account_currency(tax.account_head)
|
||||||
|
|
||||||
|
if self.doctype == "Purchase Invoice":
|
||||||
|
dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
|
||||||
|
rev_dr_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
|
||||||
|
else:
|
||||||
|
dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
|
||||||
|
rev_dr_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
|
||||||
|
|
||||||
|
party = self.supplier if self.doctype == "Purchase Invoice" else self.customer
|
||||||
|
unallocated_amount = tax.tax_amount - tax.allocated_amount
|
||||||
|
if tax_map.get(tax.account_head):
|
||||||
|
amount = tax_map.get(tax.account_head)
|
||||||
|
if amount < unallocated_amount:
|
||||||
|
unallocated_amount = amount
|
||||||
|
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": tax.account_head,
|
||||||
|
"against": party,
|
||||||
|
dr_or_cr: unallocated_amount,
|
||||||
|
dr_or_cr + "_in_account_currency": unallocated_amount
|
||||||
|
if account_currency==self.company_currency
|
||||||
|
else unallocated_amount,
|
||||||
|
"cost_center": tax.cost_center
|
||||||
|
}, account_currency, item=tax))
|
||||||
|
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": pe.advance_tax_account,
|
||||||
|
"against": party,
|
||||||
|
rev_dr_cr: unallocated_amount,
|
||||||
|
rev_dr_cr + "_in_account_currency": unallocated_amount
|
||||||
|
if account_currency==self.company_currency
|
||||||
|
else unallocated_amount,
|
||||||
|
"cost_center": tax.cost_center
|
||||||
|
}, account_currency, item=tax))
|
||||||
|
|
||||||
|
frappe.db.set_value("Advance Taxes and Charges", tax.name, "allocated_amount",
|
||||||
|
tax.allocated_amount + unallocated_amount)
|
||||||
|
|
||||||
|
tax_map[tax.account_head] -= unallocated_amount
|
||||||
|
|
||||||
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||||
from erpnext.controllers.status_updater import get_allowance_for
|
from erpnext.controllers.status_updater import get_allowance_for
|
||||||
item_allowance = {}
|
item_allowance = {}
|
||||||
@@ -1240,7 +1324,6 @@ def get_advance_payment_entries(party_type, party, party_account, order_doctype,
|
|||||||
|
|
||||||
return list(payment_entries_against_order) + list(unallocated_payment_entries)
|
return list(payment_entries_against_order) + list(unallocated_payment_entries)
|
||||||
|
|
||||||
|
|
||||||
def update_invoice_status():
|
def update_invoice_status():
|
||||||
# Daily update the status of the invoices
|
# Daily update the status of the invoices
|
||||||
|
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ class BuyingController(StockController):
|
|||||||
stock_and_asset_items_amount += flt(d.base_net_amount)
|
stock_and_asset_items_amount += flt(d.base_net_amount)
|
||||||
last_item_idx = d.idx
|
last_item_idx = d.idx
|
||||||
|
|
||||||
total_valuation_amount = sum([flt(d.base_tax_amount_after_discount_amount) for d in self.get("taxes")
|
total_valuation_amount = sum(flt(d.base_tax_amount_after_discount_amount) for d in self.get("taxes")
|
||||||
if d.category in ["Valuation", "Valuation and Total"]])
|
if d.category in ["Valuation", "Valuation and Total"])
|
||||||
|
|
||||||
valuation_amount_adjustment = total_valuation_amount
|
valuation_amount_adjustment = total_valuation_amount
|
||||||
for i, item in enumerate(self.get("items")):
|
for i, item in enumerate(self.get("items")):
|
||||||
@@ -325,7 +325,7 @@ class BuyingController(StockController):
|
|||||||
def update_raw_materials_supplied_based_on_stock_entries(self):
|
def update_raw_materials_supplied_based_on_stock_entries(self):
|
||||||
self.set('supplied_items', [])
|
self.set('supplied_items', [])
|
||||||
|
|
||||||
purchase_orders = set([d.purchase_order for d in self.items])
|
purchase_orders = set(d.purchase_order for d in self.items)
|
||||||
|
|
||||||
# qty of raw materials backflushed (for each item per purchase order)
|
# qty of raw materials backflushed (for each item per purchase order)
|
||||||
backflushed_raw_materials_map = get_backflushed_subcontracted_raw_materials(purchase_orders)
|
backflushed_raw_materials_map = get_backflushed_subcontracted_raw_materials(purchase_orders)
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
fields = get_fields("Customer", fields)
|
fields = get_fields("Customer", fields)
|
||||||
|
|
||||||
searchfields = frappe.get_meta("Customer").get_search_fields()
|
searchfields = frappe.get_meta("Customer").get_search_fields()
|
||||||
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
|
searchfields = " or ".join(field + " like %(txt)s" for field in searchfields)
|
||||||
|
|
||||||
return frappe.db.sql("""select {fields} from `tabCustomer`
|
return frappe.db.sql("""select {fields} from `tabCustomer`
|
||||||
where docstatus < 2
|
where docstatus < 2
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ class SellingController(StockController):
|
|||||||
self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
|
self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
|
||||||
|
|
||||||
def get_po_nos(self, ref_doctype, ref_fieldname, po_nos):
|
def get_po_nos(self, ref_doctype, ref_fieldname, po_nos):
|
||||||
doc_list = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
|
doc_list = list(set(d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)))
|
||||||
if doc_list:
|
if doc_list:
|
||||||
po_nos += [d.po_no for d in frappe.get_all(ref_doctype, 'po_no', filters = {'name': ('in', doc_list)}) if d.get('po_no')]
|
po_nos += [d.po_no for d in frappe.get_all(ref_doctype, 'po_no', filters = {'name': ('in', doc_list)}) if d.get('po_no')]
|
||||||
|
|
||||||
|
|||||||
@@ -299,8 +299,8 @@ class StatusUpdater(Document):
|
|||||||
args['name'] = self.get(args['percent_join_field_parent'])
|
args['name'] = self.get(args['percent_join_field_parent'])
|
||||||
self._update_percent_field(args, update_modified)
|
self._update_percent_field(args, update_modified)
|
||||||
else:
|
else:
|
||||||
distinct_transactions = set([d.get(args['percent_join_field'])
|
distinct_transactions = set(d.get(args['percent_join_field'])
|
||||||
for d in self.get_all_children(args['source_dt'])])
|
for d in self.get_all_children(args['source_dt']))
|
||||||
|
|
||||||
for name in distinct_transactions:
|
for name in distinct_transactions:
|
||||||
if name:
|
if name:
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
def get_serialized_items(self):
|
def get_serialized_items(self):
|
||||||
serialized_items = []
|
serialized_items = []
|
||||||
item_codes = list(set([d.item_code for d in self.get("items")]))
|
item_codes = list(set(d.item_code for d in self.get("items")))
|
||||||
if item_codes:
|
if item_codes:
|
||||||
serialized_items = frappe.db.sql_list("""select name from `tabItem`
|
serialized_items = frappe.db.sql_list("""select name from `tabItem`
|
||||||
where has_serial_no=1 and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
|
where has_serial_no=1 and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
|
||||||
@@ -324,8 +324,8 @@ class StockController(AccountsController):
|
|||||||
def validate_warehouse(self):
|
def validate_warehouse(self):
|
||||||
from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company
|
from erpnext.stock.utils import validate_disabled_warehouse, validate_warehouse_company
|
||||||
|
|
||||||
warehouses = list(set([d.warehouse for d in
|
warehouses = list(set(d.warehouse for d in
|
||||||
self.get("items") if getattr(d, "warehouse", None)]))
|
self.get("items") if getattr(d, "warehouse", None)))
|
||||||
|
|
||||||
target_warehouses = list(set([d.target_warehouse for d in
|
target_warehouses = list(set([d.target_warehouse for d in
|
||||||
self.get("items") if getattr(d, "target_warehouse", None)]))
|
self.get("items") if getattr(d, "target_warehouse", None)]))
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
if item.item_code and item.get('item_tax_template'):
|
if item.item_code and item.get('item_tax_template'):
|
||||||
item_doc = frappe.get_cached_doc("Item", item.item_code)
|
item_doc = frappe.get_cached_doc("Item", item.item_code)
|
||||||
args = {
|
args = {
|
||||||
|
'net_rate': item.net_rate or item.rate,
|
||||||
'tax_category': self.doc.get('tax_category'),
|
'tax_category': self.doc.get('tax_category'),
|
||||||
'posting_date': self.doc.get('posting_date'),
|
'posting_date': self.doc.get('posting_date'),
|
||||||
'bill_date': self.doc.get('bill_date'),
|
'bill_date': self.doc.get('bill_date'),
|
||||||
@@ -77,10 +78,12 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
|
taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
|
||||||
|
|
||||||
if item.item_tax_template not in taxes:
|
if taxes:
|
||||||
frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format(
|
if item.item_tax_template not in taxes:
|
||||||
item.idx, frappe.bold(item.item_code)
|
item.item_tax_template = taxes[0]
|
||||||
))
|
frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format(
|
||||||
|
item.idx, frappe.bold(item.item_code)
|
||||||
|
))
|
||||||
|
|
||||||
def validate_conversion_rate(self):
|
def validate_conversion_rate(self):
|
||||||
# validate conversion rate
|
# validate conversion rate
|
||||||
@@ -375,10 +378,10 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
def manipulate_grand_total_for_inclusive_tax(self):
|
def manipulate_grand_total_for_inclusive_tax(self):
|
||||||
# if fully inclusive taxes and diff
|
# if fully inclusive taxes and diff
|
||||||
if self.doc.get("taxes") and any([cint(t.included_in_print_rate) for t in self.doc.get("taxes")]):
|
if self.doc.get("taxes") and any(cint(t.included_in_print_rate) for t in self.doc.get("taxes")):
|
||||||
last_tax = self.doc.get("taxes")[-1]
|
last_tax = self.doc.get("taxes")[-1]
|
||||||
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
|
non_inclusive_tax_amount = sum(flt(d.tax_amount_after_discount_amount)
|
||||||
for d in self.doc.get("taxes") if not d.included_in_print_rate])
|
for d in self.doc.get("taxes") if not d.included_in_print_rate)
|
||||||
|
|
||||||
diff = self.doc.total + non_inclusive_tax_amount \
|
diff = self.doc.total + non_inclusive_tax_amount \
|
||||||
- flt(last_tax.total, last_tax.precision("total"))
|
- flt(last_tax.total, last_tax.precision("total"))
|
||||||
@@ -518,8 +521,8 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
def calculate_total_advance(self):
|
def calculate_total_advance(self):
|
||||||
if self.doc.docstatus < 2:
|
if self.doc.docstatus < 2:
|
||||||
total_allocated_amount = sum([flt(adv.allocated_amount, adv.precision("allocated_amount"))
|
total_allocated_amount = sum(flt(adv.allocated_amount, adv.precision("allocated_amount"))
|
||||||
for adv in self.doc.get("advances")])
|
for adv in self.doc.get("advances"))
|
||||||
|
|
||||||
self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
|
self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
|
||||||
|
|
||||||
@@ -619,7 +622,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
if self.doc.doctype == "Sales Invoice" \
|
if self.doc.doctype == "Sales Invoice" \
|
||||||
and self.doc.paid_amount > self.doc.grand_total and not self.doc.is_return \
|
and self.doc.paid_amount > self.doc.grand_total and not self.doc.is_return \
|
||||||
and any([d.type == "Cash" for d in self.doc.payments]):
|
and any(d.type == "Cash" for d in self.doc.payments):
|
||||||
grand_total = self.doc.rounded_total or self.doc.grand_total
|
grand_total = self.doc.rounded_total or self.doc.grand_total
|
||||||
base_grand_total = self.doc.base_rounded_total or self.doc.base_grand_total
|
base_grand_total = self.doc.base_rounded_total or self.doc.base_grand_total
|
||||||
|
|
||||||
@@ -683,7 +686,6 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
self.calculate_paid_amount()
|
self.calculate_paid_amount()
|
||||||
|
|
||||||
|
|
||||||
def get_itemised_tax_breakup_html(doc):
|
def get_itemised_tax_breakup_html(doc):
|
||||||
if not doc.taxes:
|
if not doc.taxes:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class TestMapper(unittest.TestCase):
|
|||||||
|
|
||||||
# Assert that all inserted items are present in updated sales order
|
# Assert that all inserted items are present in updated sales order
|
||||||
src_items = item_list_1 + item_list_2 + item_list_3
|
src_items = item_list_1 + item_list_2 + item_list_3
|
||||||
self.assertEqual(set([d for d in src_items]),
|
self.assertEqual(set(d for d in src_items),
|
||||||
set([d.item_code for d in updated_so.items]))
|
set(d.item_code for d in updated_so.items))
|
||||||
|
|
||||||
|
|
||||||
def make_quotation(self, item_list, customer):
|
def make_quotation(self, item_list, customer):
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def post_process(doctype, data):
|
|||||||
doc.set_indicator()
|
doc.set_indicator()
|
||||||
|
|
||||||
doc.status_display = ", ".join(doc.status_display)
|
doc.status_display = ", ".join(doc.status_display)
|
||||||
doc.items_preview = ", ".join([d.item_name for d in doc.items if d.item_name])
|
doc.items_preview = ", ".join(d.item_name for d in doc.items if d.item_name)
|
||||||
result.append(doc)
|
result.append(doc)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ frappe.ui.form.on('Assessment Result', {
|
|||||||
if (!frm.doc.__islocal) {
|
if (!frm.doc.__islocal) {
|
||||||
frm.trigger('setup_chart');
|
frm.trigger('setup_chart');
|
||||||
}
|
}
|
||||||
frm.set_df_property('details', 'read_only', 1);
|
|
||||||
|
frm.get_field('details').grid.cannot_add_rows = true;
|
||||||
|
|
||||||
frm.set_query('course', function() {
|
frm.set_query('course', function() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -33,21 +33,21 @@ class Patient(Document):
|
|||||||
self.reload() # self.notify_update()
|
self.reload() # self.notify_update()
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
if self.customer:
|
if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient'):
|
||||||
customer = frappe.get_doc('Customer', self.customer)
|
if self.customer:
|
||||||
if self.customer_group:
|
customer = frappe.get_doc('Customer', self.customer)
|
||||||
customer.customer_group = self.customer_group
|
if self.customer_group:
|
||||||
if self.territory:
|
customer.customer_group = self.customer_group
|
||||||
customer.territory = self.territory
|
if self.territory:
|
||||||
|
customer.territory = self.territory
|
||||||
|
|
||||||
customer.customer_name = self.patient_name
|
customer.customer_name = self.patient_name
|
||||||
customer.default_price_list = self.default_price_list
|
customer.default_price_list = self.default_price_list
|
||||||
customer.default_currency = self.default_currency
|
customer.default_currency = self.default_currency
|
||||||
customer.language = self.language
|
customer.language = self.language
|
||||||
customer.ignore_mandatory = True
|
customer.ignore_mandatory = True
|
||||||
customer.save(ignore_permissions=True)
|
customer.save(ignore_permissions=True)
|
||||||
else:
|
else:
|
||||||
if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient'):
|
|
||||||
create_customer(self)
|
create_customer(self)
|
||||||
|
|
||||||
def set_full_name(self):
|
def set_full_name(self):
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ class JobCard(Document):
|
|||||||
'docstatus': ('!=', 2)}, fields = 'sum(transferred_qty) as qty', group_by='operation_id')
|
'docstatus': ('!=', 2)}, fields = 'sum(transferred_qty) as qty', group_by='operation_id')
|
||||||
|
|
||||||
if job_cards:
|
if job_cards:
|
||||||
qty = min([d.qty for d in job_cards])
|
qty = min(d.qty for d in job_cards)
|
||||||
|
|
||||||
doc.db_set('material_transferred_for_manufacturing', qty)
|
doc.db_set('material_transferred_for_manufacturing', qty)
|
||||||
|
|
||||||
|
|||||||
@@ -1,494 +1,19 @@
|
|||||||
execute:import unidecode # new requirement
|
|
||||||
erpnext.patches.v8_0.move_perpetual_inventory_setting
|
|
||||||
erpnext.patches.v8_9.set_print_zero_amount_taxes
|
|
||||||
erpnext.patches.v12_0.update_is_cancelled_field
|
erpnext.patches.v12_0.update_is_cancelled_field
|
||||||
erpnext.patches.v11_0.rename_production_order_to_work_order
|
erpnext.patches.v11_0.rename_production_order_to_work_order
|
||||||
erpnext.patches.v11_0.refactor_naming_series
|
erpnext.patches.v11_0.refactor_naming_series
|
||||||
erpnext.patches.v11_0.refactor_autoname_naming
|
erpnext.patches.v11_0.refactor_autoname_naming
|
||||||
erpnext.patches.v10_0.rename_schools_to_education
|
|
||||||
erpnext.patches.v4_0.validate_v3_patch
|
|
||||||
erpnext.patches.v4_0.fix_employee_user_id
|
|
||||||
erpnext.patches.v4_0.remove_employee_role_if_no_employee
|
|
||||||
erpnext.patches.v4_0.update_user_properties
|
|
||||||
erpnext.patches.v4_0.apply_user_permissions
|
|
||||||
erpnext.patches.v4_0.move_warehouse_user_to_restrictions
|
|
||||||
erpnext.patches.v4_0.global_defaults_to_system_settings
|
|
||||||
erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule
|
|
||||||
execute:frappe.reload_doc("accounts", "doctype", "POS Payment Method") #2020-05-28
|
execute:frappe.reload_doc("accounts", "doctype", "POS Payment Method") #2020-05-28
|
||||||
execute:frappe.reload_doc("HR", "doctype", "HR Settings") #2020-01-16 #2020-07-24
|
execute:frappe.reload_doc("HR", "doctype", "HR Settings") #2020-01-16 #2020-07-24
|
||||||
execute:frappe.reload_doc('stock', 'doctype', 'warehouse') # 2017-04-24
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31
|
|
||||||
execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('selling', 'doctype', 'quotation') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('stock', 'doctype', 'delivery_note') # 2014-01-29
|
|
||||||
erpnext.patches.v4_0.reload_sales_print_format
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'purchase_invoice') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('buying', 'doctype', 'purchase_order') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('buying', 'doctype', 'supplier_quotation') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('stock', 'doctype', 'purchase_receipt') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'pos_setting') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('selling', 'doctype', 'customer') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('buying', 'doctype', 'supplier') # 2014-01-29
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'asset_category')
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'pricing_rule')
|
|
||||||
erpnext.patches.v4_0.map_charge_to_taxes_and_charges
|
|
||||||
execute:frappe.reload_doc('support', 'doctype', 'newsletter') # 2014-01-31
|
|
||||||
execute:frappe.reload_doc('hr', 'doctype', 'employee') # 2014-02-03
|
|
||||||
execute:frappe.db.sql("update tabPage set module='Core' where name='Setup'")
|
|
||||||
erpnext.patches.v5_2.change_item_selects_to_checks
|
|
||||||
execute:frappe.reload_doctype('Item')
|
|
||||||
erpnext.patches.v4_0.fields_to_be_renamed
|
|
||||||
erpnext.patches.v4_0.rename_sitemap_to_route
|
|
||||||
erpnext.patches.v7_0.re_route #2016-06-27
|
|
||||||
erpnext.patches.v4_0.fix_contact_address
|
|
||||||
erpnext.patches.v4_0.customer_discount_to_pricing_rule
|
|
||||||
execute:frappe.db.sql("""delete from `tabWebsite Item Group` where ifnull(item_group, '')=''""")
|
|
||||||
erpnext.patches.v4_0.remove_module_home_pages
|
|
||||||
erpnext.patches.v4_0.split_email_settings
|
|
||||||
erpnext.patches.v4_0.import_country_codes
|
|
||||||
erpnext.patches.v4_0.countrywise_coa
|
|
||||||
execute:frappe.delete_doc("DocType", "MIS Control")
|
|
||||||
execute:frappe.delete_doc("Page", "Financial Statements")
|
|
||||||
execute:frappe.delete_doc("DocType", "Stock Ledger")
|
|
||||||
execute:frappe.delete_doc("DocType", "Grade")
|
|
||||||
execute:frappe.db.sql("delete from `tabWebsite Item Group` where ifnull(item_group, '')=''")
|
|
||||||
execute:frappe.delete_doc("Print Format", "SalesInvoice")
|
|
||||||
execute:import frappe.defaults;frappe.defaults.clear_default("price_list_currency")
|
|
||||||
erpnext.patches.v4_0.update_account_root_type
|
|
||||||
execute:frappe.delete_doc("Report", "Purchase In Transit")
|
|
||||||
erpnext.patches.v4_0.new_address_template
|
|
||||||
execute:frappe.delete_doc("DocType", "SMS Control")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Bulk SMS") #2015-08-18
|
|
||||||
erpnext.patches.v4_0.fix_case_of_hr_module_def
|
|
||||||
erpnext.patches.v4_0.fix_address_template
|
|
||||||
|
|
||||||
# WATCHOUT: This patch reload's documents
|
|
||||||
erpnext.patches.v4_0.reset_permissions_for_masters
|
|
||||||
erpnext.patches.v6_20x.rename_project_name_to_project #2016-03-14
|
|
||||||
|
|
||||||
erpnext.patches.v4_0.update_tax_amount_after_discount
|
|
||||||
execute:frappe.permissions.reset_perms("GL Entry") #2014-06-09
|
|
||||||
execute:frappe.permissions.reset_perms("Stock Ledger Entry") #2014-06-09
|
|
||||||
erpnext.patches.v4_0.create_custom_fields_for_india_specific_fields
|
|
||||||
erpnext.patches.v4_0.save_default_letterhead
|
|
||||||
erpnext.patches.v4_0.update_custom_print_formats_for_renamed_fields
|
|
||||||
erpnext.patches.v4_0.update_other_charges_in_custom_purchase_print_formats
|
|
||||||
erpnext.patches.v4_0.create_price_list_if_missing
|
|
||||||
execute:frappe.db.sql("update `tabItem` set end_of_life=null where end_of_life='0000-00-00'") #2014-06-16
|
|
||||||
erpnext.patches.v4_0.update_users_report_view_settings
|
|
||||||
erpnext.patches.v4_0.set_pricing_rule_for_buying_or_selling
|
|
||||||
erpnext.patches.v4_1.set_outgoing_email_footer
|
|
||||||
erpnext.patches.v4_1.fix_sales_order_delivered_status
|
|
||||||
erpnext.patches.v4_1.fix_delivery_and_billing_status
|
|
||||||
execute:frappe.db.sql("update `tabAccount` set root_type='Liability' where root_type='Income' and report_type='Balance Sheet'")
|
|
||||||
execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool") # 29-07-2014
|
|
||||||
execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool Detail") # 29-07-2014
|
|
||||||
execute:frappe.delete_doc("Page", "trial-balance") #2014-07-22
|
|
||||||
erpnext.patches.v4_2.delete_old_print_formats #2014-07-29
|
|
||||||
erpnext.patches.v4_2.toggle_rounded_total #2014-07-30
|
|
||||||
erpnext.patches.v4_2.fix_account_master_type
|
|
||||||
erpnext.patches.v4_2.update_project_milestones
|
|
||||||
erpnext.patches.v4_2.add_currency_turkish_lira #2014-08-08
|
|
||||||
execute:frappe.delete_doc("DocType", "Landed Cost Wizard")
|
|
||||||
erpnext.patches.v4_2.default_website_style
|
|
||||||
erpnext.patches.v4_2.set_company_country
|
|
||||||
erpnext.patches.v4_2.update_sales_order_invoice_field_name
|
|
||||||
erpnext.patches.v4_2.seprate_manufacture_and_repack
|
|
||||||
execute:frappe.delete_doc("Report", "Warehouse-Wise Stock Balance")
|
|
||||||
execute:frappe.delete_doc("DocType", "Purchase Request")
|
|
||||||
execute:frappe.delete_doc("DocType", "Purchase Request Item")
|
|
||||||
erpnext.patches.v4_2.recalculate_bom_cost
|
|
||||||
erpnext.patches.v4_2.fix_gl_entries_for_stock_transactions
|
|
||||||
erpnext.patches.v4_2.update_requested_and_ordered_qty #2021-03-31
|
erpnext.patches.v4_2.update_requested_and_ordered_qty #2021-03-31
|
||||||
execute:frappe.rename_doc("DocType", "Support Ticket", "Issue", force=True)
|
|
||||||
erpnext.patches.v4_4.make_email_accounts
|
|
||||||
execute:frappe.delete_doc("DocType", "Contact Control")
|
|
||||||
erpnext.patches.v4_2.discount_amount
|
|
||||||
erpnext.patches.v4_2.reset_bom_costs
|
|
||||||
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
|
||||||
erpnext.patches.v5_0.update_dn_against_doc_fields
|
|
||||||
execute:frappe.db.sql("update `tabMaterial Request` set material_request_type = 'Material Transfer' where material_request_type = 'Transfer'")
|
|
||||||
execute:frappe.reload_doc('stock', 'doctype', 'item')
|
|
||||||
erpnext.patches.v5_0.set_default_company_in_bom
|
|
||||||
execute:frappe.reload_doc('crm', 'doctype', 'lead')
|
|
||||||
execute:frappe.reload_doc('crm', 'doctype', 'opportunity')
|
|
||||||
erpnext.patches.v5_0.rename_taxes_and_charges_master
|
|
||||||
erpnext.patches.v5_1.sales_bom_rename
|
|
||||||
erpnext.patches.v5_0.rename_table_fieldnames
|
|
||||||
execute:frappe.db.sql("update `tabJournal Entry` set voucher_type='Journal Entry' where ifnull(voucher_type, '')=''")
|
|
||||||
erpnext.patches.v5_0.is_group
|
|
||||||
erpnext.patches.v4_2.party_model
|
|
||||||
erpnext.patches.v5_0.party_model_patch_fix
|
|
||||||
erpnext.patches.v4_1.fix_jv_remarks
|
|
||||||
erpnext.patches.v4_2.update_landed_cost_voucher
|
|
||||||
erpnext.patches.v4_2.set_item_has_batch
|
|
||||||
erpnext.patches.v4_2.update_stock_uom_for_dn_in_sle
|
|
||||||
erpnext.patches.v5_0.recalculate_total_amount_in_jv
|
|
||||||
erpnext.patches.v5_0.update_companywise_payment_account
|
|
||||||
erpnext.patches.v5_0.remove_birthday_events
|
|
||||||
erpnext.patches.v5_0.update_item_name_in_bom
|
|
||||||
erpnext.patches.v5_0.rename_customer_issue
|
|
||||||
erpnext.patches.v5_0.rename_total_fields
|
|
||||||
erpnext.patches.v5_0.new_crm_module
|
|
||||||
erpnext.patches.v5_0.rename_customer_issue
|
|
||||||
erpnext.patches.v5_0.update_material_transfer_for_manufacture
|
|
||||||
execute:frappe.reload_doc('crm', 'doctype', 'opportunity_item')
|
|
||||||
erpnext.patches.v5_0.update_item_description_and_image
|
|
||||||
erpnext.patches.v5_0.update_material_transferred_for_manufacturing
|
|
||||||
erpnext.patches.v5_0.stock_entry_update_value
|
|
||||||
erpnext.patches.v5_0.convert_stock_reconciliation
|
|
||||||
erpnext.patches.v5_0.update_projects
|
|
||||||
erpnext.patches.v5_0.item_patches
|
|
||||||
erpnext.patches.v5_0.update_journal_entry_title
|
|
||||||
erpnext.patches.v5_0.taxes_and_totals_in_party_currency
|
|
||||||
erpnext.patches.v5_0.replace_renamed_fields_in_custom_scripts_and_print_formats
|
|
||||||
erpnext.patches.v5_0.update_from_bom
|
|
||||||
erpnext.patches.v5_0.update_account_types
|
|
||||||
erpnext.patches.v5_0.update_sms_sender
|
|
||||||
erpnext.patches.v5_0.set_appraisal_remarks
|
|
||||||
erpnext.patches.v5_0.update_time_log_title
|
|
||||||
erpnext.patches.v7_0.create_warehouse_nestedset
|
|
||||||
erpnext.patches.v7_0.merge_account_type_stock_and_warehouse_to_stock
|
|
||||||
erpnext.patches.v7_0.set_is_group_for_warehouse
|
|
||||||
erpnext.patches.v7_2.stock_uom_in_selling
|
|
||||||
erpnext.patches.v4_2.repost_sle_for_si_with_no_warehouse
|
|
||||||
erpnext.patches.v5_0.newsletter
|
|
||||||
execute:frappe.delete_doc("DocType", "Chart of Accounts")
|
|
||||||
execute:frappe.delete_doc("DocType", "Style Settings")
|
|
||||||
erpnext.patches.v5_0.update_opportunity
|
|
||||||
erpnext.patches.v5_0.opportunity_not_submittable
|
|
||||||
execute:frappe.permissions.reset_perms("Purchase Taxes and Charges Template") #2014-06-09
|
|
||||||
execute:frappe.permissions.reset_perms("Expense Claim Type") #2014-06-19
|
|
||||||
erpnext.patches.v5_0.execute_on_doctype_update
|
|
||||||
erpnext.patches.v4_2.fix_recurring_orders
|
|
||||||
erpnext.patches.v4_2.delete_gl_entries_for_cancelled_invoices
|
|
||||||
erpnext.patches.v5_0.project_costing
|
|
||||||
erpnext.patches.v5_0.update_temporary_account
|
|
||||||
erpnext.patches.v5_0.update_advance_paid
|
|
||||||
erpnext.patches.v5_0.link_warehouse_with_account
|
|
||||||
execute:frappe.delete_doc("Page", "stock-ledger")
|
|
||||||
execute:frappe.delete_doc("Page","stock-level")
|
|
||||||
erpnext.patches.v5_0.reclculate_planned_operating_cost_in_production_order
|
|
||||||
erpnext.patches.v5_0.repost_requested_qty
|
|
||||||
erpnext.patches.v5_0.fix_taxes_and_totals_in_party_currency
|
|
||||||
erpnext.patches.v5_0.update_tax_amount_after_discount_in_purchase_cycle
|
|
||||||
erpnext.patches.v5_0.rename_pos_setting
|
|
||||||
erpnext.patches.v5_0.update_operation_description
|
|
||||||
erpnext.patches.v5_0.set_footer_address
|
|
||||||
execute:frappe.db.set_value("Backup Manager", None, "send_backups_to_dropbox", 1 if frappe.db.get_value("Backup Manager", None, "upload_backups_to_dropbox") in ("Daily", "Weekly") else 0)
|
|
||||||
execute:frappe.db.sql_list("delete from `tabDocPerm` where parent='Issue' and modified_by='Administrator' and role='Guest'")
|
|
||||||
erpnext.patches.v5_0.update_item_and_description_again
|
|
||||||
erpnext.patches.v6_0.multi_currency
|
|
||||||
erpnext.patches.v7_0.create_budget_record
|
|
||||||
erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party
|
|
||||||
erpnext.patches.v5_0.portal_fixes
|
|
||||||
erpnext.patches.v5_0.reset_values_in_tools # 02-05-2016
|
|
||||||
execute:frappe.delete_doc("Page", "users")
|
|
||||||
erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again
|
|
||||||
erpnext.patches.v5_0.index_on_account_and_gl_entry
|
|
||||||
execute:frappe.db.sql("""delete from `tabProject Task`""")
|
|
||||||
erpnext.patches.v5_0.update_item_desc_in_invoice
|
|
||||||
erpnext.patches.v5_1.fix_against_account
|
|
||||||
execute:frappe.rename_doc("DocType", "Salary Manager", "Process Payroll", force=True)
|
|
||||||
erpnext.patches.v5_1.rename_roles
|
|
||||||
erpnext.patches.v5_1.default_bom
|
|
||||||
execute:frappe.delete_doc("DocType", "Party Type")
|
|
||||||
execute:frappe.delete_doc("Module Def", "Contacts")
|
|
||||||
erpnext.patches.v5_4.fix_reserved_qty_and_sle_for_packed_items # 30-07-2015
|
|
||||||
execute:frappe.reload_doctype("Leave Type")
|
|
||||||
execute:frappe.db.sql("update `tabLeave Type` set include_holiday=0")
|
|
||||||
erpnext.patches.v5_4.set_root_and_report_type
|
|
||||||
erpnext.patches.v5_4.notify_system_managers_regarding_wrong_tax_calculation
|
|
||||||
erpnext.patches.v5_4.fix_invoice_outstanding
|
|
||||||
execute:frappe.db.sql("update `tabStock Ledger Entry` set stock_queue = '[]' where voucher_type = 'Stock Reconciliation' and ifnull(qty_after_transaction, 0) = 0")
|
|
||||||
erpnext.patches.v5_4.fix_missing_item_images
|
|
||||||
erpnext.patches.v5_4.stock_entry_additional_costs
|
|
||||||
erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14
|
|
||||||
erpnext.patches.v5_7.update_item_description_based_on_item_master
|
erpnext.patches.v5_7.update_item_description_based_on_item_master
|
||||||
erpnext.patches.v5_7.item_template_attributes
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Manage Variants")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item")
|
|
||||||
erpnext.patches.v4_2.repost_reserved_qty #2021-03-31
|
erpnext.patches.v4_2.repost_reserved_qty #2021-03-31
|
||||||
erpnext.patches.v5_4.update_purchase_cost_against_project
|
|
||||||
erpnext.patches.v5_8.update_order_reference_in_return_entries
|
|
||||||
erpnext.patches.v5_8.add_credit_note_print_heading
|
|
||||||
execute:frappe.delete_doc_if_exists("Print Format", "Credit Note - Negative Invoice")
|
|
||||||
|
|
||||||
# V6.0
|
|
||||||
erpnext.patches.v6_0.set_default_title # 2015-09-03
|
|
||||||
erpnext.patches.v6_0.default_activity_rate
|
|
||||||
execute:frappe.db.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1)
|
|
||||||
execute:frappe.db.sql("""update `tabProject` set percent_complete=round(percent_complete, 2) where percent_complete is not null""")
|
|
||||||
erpnext.patches.v6_0.fix_outstanding_amount
|
|
||||||
erpnext.patches.v6_0.fix_planned_qty
|
|
||||||
erpnext.patches.v6_2.remove_newsletter_duplicates
|
|
||||||
erpnext.patches.v6_2.fix_missing_default_taxes_and_lead
|
|
||||||
erpnext.patches.v6_3.convert_applicable_territory
|
|
||||||
erpnext.patches.v6_4.round_status_updater_percentages
|
|
||||||
erpnext.patches.v6_4.repost_gle_for_journal_entries_where_reference_name_missing
|
|
||||||
erpnext.patches.v6_4.fix_journal_entries_due_to_reconciliation
|
|
||||||
erpnext.patches.v6_4.fix_status_in_sales_and_purchase_order
|
|
||||||
erpnext.patches.v6_4.fix_modified_in_sales_order_and_purchase_order
|
|
||||||
erpnext.patches.v6_4.fix_duplicate_bins
|
|
||||||
erpnext.patches.v6_4.fix_sales_order_maintenance_status
|
|
||||||
erpnext.patches.v6_4.email_digest_update
|
|
||||||
|
|
||||||
# delete shopping cart doctypes
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Applicable Territory")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Price List")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges Master")
|
|
||||||
|
|
||||||
erpnext.patches.v6_4.set_user_in_contact
|
|
||||||
erpnext.patches.v6_4.make_image_thumbnail #2015-10-20
|
|
||||||
erpnext.patches.v6_5.show_in_website_for_template_item
|
|
||||||
erpnext.patches.v6_4.fix_expense_included_in_valuation
|
|
||||||
execute:frappe.delete_doc_if_exists("Report", "Item-wise Last Purchase Rate")
|
|
||||||
erpnext.patches.v6_6.fix_website_image
|
|
||||||
erpnext.patches.v6_6.remove_fiscal_year_from_leave_allocation
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Stock UOM Replace Utility")
|
|
||||||
erpnext.patches.v6_8.make_webform_standard #2015-11-23
|
|
||||||
erpnext.patches.v6_8.move_drop_ship_to_po_items
|
|
||||||
erpnext.patches.v6_10.fix_ordered_received_billed
|
|
||||||
erpnext.patches.v6_10.fix_jv_total_amount #2015-11-30
|
|
||||||
erpnext.patches.v6_10.email_digest_default_quote
|
|
||||||
erpnext.patches.v6_10.fix_billed_amount_in_drop_ship_po
|
|
||||||
erpnext.patches.v6_10.fix_delivery_status_of_drop_ship_item #2015-12-08
|
|
||||||
erpnext.patches.v5_8.tax_rule #2015-12-08
|
|
||||||
erpnext.patches.v6_12.set_overdue_tasks
|
|
||||||
erpnext.patches.v6_16.update_billing_status_in_dn_and_pr
|
|
||||||
erpnext.patches.v6_16.create_manufacturer_records
|
|
||||||
execute:frappe.db.sql("update `tabPricing Rule` set title=name where title='' or title is null") #2016-01-27
|
|
||||||
erpnext.patches.v6_20.set_party_account_currency_in_orders
|
|
||||||
erpnext.patches.v6_19.comment_feed_communication
|
|
||||||
erpnext.patches.v6_21.fix_reorder_level
|
|
||||||
erpnext.patches.v6_21.rename_material_request_fields
|
|
||||||
erpnext.patches.v6_23.update_stopped_status_to_closed
|
|
||||||
erpnext.patches.v6_24.set_recurring_id
|
|
||||||
erpnext.patches.v6_20x.set_compact_print
|
|
||||||
execute:frappe.delete_doc_if_exists("Web Form", "contact") #2016-03-10
|
|
||||||
erpnext.patches.v6_20x.remove_fiscal_year_from_holiday_list
|
|
||||||
erpnext.patches.v6_24.map_customer_address_to_shipping_address_on_po
|
|
||||||
erpnext.patches.v6_27.fix_recurring_order_status
|
|
||||||
erpnext.patches.v6_20x.update_product_bundle_description
|
|
||||||
erpnext.patches.v7_0.update_party_status #2016-09-22
|
|
||||||
erpnext.patches.v7_0.remove_features_setup
|
|
||||||
erpnext.patches.v7_0.update_home_page
|
|
||||||
execute:frappe.delete_doc_if_exists("Page", "financial-analytics")
|
|
||||||
erpnext.patches.v7_0.update_project_in_gl_entry
|
|
||||||
execute:frappe.db.sql('update tabQuotation set status="Cancelled" where docstatus=2')
|
|
||||||
execute:frappe.rename_doc("DocType", "Payments", "Sales Invoice Payment", force=True)
|
|
||||||
erpnext.patches.v7_0.update_mins_to_first_response
|
|
||||||
erpnext.patches.v6_20x.repost_valuation_rate_for_negative_inventory
|
|
||||||
erpnext.patches.v7_0.migrate_mode_of_payments_v6_to_v7
|
|
||||||
erpnext.patches.v7_0.system_settings_setup_complete
|
|
||||||
erpnext.patches.v7_0.set_naming_series_for_timesheet #2016-07-27
|
|
||||||
execute:frappe.reload_doc('projects', 'doctype', 'project')
|
|
||||||
execute:frappe.reload_doc('projects', 'doctype', 'project_user')
|
|
||||||
erpnext.patches.v7_0.convert_timelogbatch_to_timesheet
|
|
||||||
erpnext.patches.v7_0.convert_timelog_to_timesheet
|
|
||||||
erpnext.patches.v7_0.move_timelogbatch_from_salesinvoiceitem_to_salesinvoicetimesheet
|
|
||||||
erpnext.patches.v7_0.remove_doctypes_and_reports #2016-10-29
|
|
||||||
erpnext.patches.v7_0.update_maintenance_module_in_doctype
|
|
||||||
erpnext.patches.v7_0.update_prevdoc_values_for_supplier_quotation_item
|
|
||||||
erpnext.patches.v7_0.rename_advance_table_fields
|
|
||||||
erpnext.patches.v7_0.rename_salary_components
|
|
||||||
erpnext.patches.v7_0.rename_prevdoc_fields
|
|
||||||
erpnext.patches.v7_0.rename_time_sheet_doctype
|
|
||||||
execute:frappe.delete_doc_if_exists("Report", "Customers Not Buying Since Long Time")
|
|
||||||
erpnext.patches.v7_0.make_is_group_fieldtype_as_check
|
|
||||||
execute:frappe.reload_doc('projects', 'doctype', 'timesheet') #2016-09-12
|
|
||||||
erpnext.patches.v7_1.rename_field_timesheet
|
|
||||||
execute:frappe.delete_doc_if_exists("Report", "Employee Holiday Attendance")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Payment Tool")
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Payment Tool Detail")
|
|
||||||
erpnext.patches.v7_0.setup_account_table_for_expense_claim_type_if_exists
|
|
||||||
erpnext.patches.v7_0.migrate_schools_to_erpnext
|
|
||||||
erpnext.patches.v7_1.update_lead_source
|
|
||||||
erpnext.patches.v6_20x.remove_customer_supplier_roles
|
|
||||||
erpnext.patches.v7_0.remove_administrator_role_in_doctypes
|
|
||||||
erpnext.patches.v7_0.rename_fee_amount_to_fee_component
|
|
||||||
erpnext.patches.v7_0.calculate_total_costing_amount
|
|
||||||
erpnext.patches.v7_0.fix_nonwarehouse_ledger_gl_entries_for_transactions
|
|
||||||
erpnext.patches.v7_0.remove_old_earning_deduction_doctypes
|
|
||||||
erpnext.patches.v7_0.make_guardian
|
|
||||||
erpnext.patches.v7_0.update_refdoc_in_landed_cost_voucher
|
|
||||||
erpnext.patches.v7_0.set_material_request_type_in_item
|
|
||||||
erpnext.patches.v7_0.rename_examination_to_assessment
|
|
||||||
erpnext.patches.v7_0.set_portal_settings
|
|
||||||
erpnext.patches.v7_0.update_change_amount_account
|
|
||||||
erpnext.patches.v7_0.fix_duplicate_icons
|
|
||||||
erpnext.patches.v7_0.repost_gle_for_pos_sales_return
|
|
||||||
erpnext.patches.v7_1.update_total_billing_hours
|
|
||||||
erpnext.patches.v7_1.update_component_type
|
|
||||||
erpnext.patches.v7_0.repost_gle_for_pos_sales_return
|
|
||||||
erpnext.patches.v7_0.update_missing_employee_in_timesheet
|
|
||||||
erpnext.patches.v7_0.update_status_for_timesheet
|
|
||||||
erpnext.patches.v7_0.set_party_name_in_payment_entry
|
|
||||||
erpnext.patches.v7_1.set_student_guardian
|
|
||||||
erpnext.patches.v7_0.update_conversion_factor_in_supplier_quotation_item
|
|
||||||
erpnext.patches.v7_1.move_sales_invoice_from_parent_to_child_timesheet
|
|
||||||
execute:frappe.db.sql("update `tabTimesheet` ts, `tabEmployee` emp set ts.employee_name = emp.employee_name where emp.name = ts.employee and ts.employee_name is null and ts.employee is not null")
|
|
||||||
erpnext.patches.v7_1.fix_link_for_customer_from_lead
|
|
||||||
execute:frappe.db.sql("delete from `tabTimesheet Detail` where NOT EXISTS (select name from `tabTimesheet` where name = `tabTimesheet Detail`.parent)")
|
|
||||||
erpnext.patches.v7_0.update_mode_of_payment_type
|
|
||||||
|
|
||||||
execute:frappe.reload_doctype('Employee') #2016-10-18
|
|
||||||
execute:frappe.db.sql("update `tabEmployee` set prefered_contact_email = IFNULL(prefered_contact_email,'') ")
|
|
||||||
execute:frappe.reload_doc("Payroll", "doctype", "salary_slip")
|
execute:frappe.reload_doc("Payroll", "doctype", "salary_slip")
|
||||||
execute:frappe.db.sql("update `tabSalary Slip` set posting_date=creation")
|
|
||||||
execute:frappe.reload_doc("stock", "doctype", "stock_settings")
|
|
||||||
erpnext.patches.v8_0.create_domain_docs #16-05-2017
|
|
||||||
erpnext.patches.v7_1.update_portal_roles
|
|
||||||
erpnext.patches.v7_1.set_total_amount_currency_in_je
|
|
||||||
finally:erpnext.patches.v7_0.update_timesheet_communications
|
|
||||||
erpnext.patches.v7_0.update_status_of_zero_amount_sales_order
|
|
||||||
erpnext.patches.v7_1.add_field_for_task_dependent
|
|
||||||
erpnext.patches.v7_0.repost_bin_qty_and_item_projected_qty
|
|
||||||
erpnext.patches.v7_1.set_prefered_contact_email
|
|
||||||
execute:frappe.reload_doc('accounts', 'doctype', 'accounts_settings')
|
|
||||||
execute:frappe.db.set_value("Accounts Settings", "Accounts Settings", "unlink_payment_on_cancellation_of_invoice", 0)
|
|
||||||
execute:frappe.db.sql("update `tabStock Entry` set total_amount = 0 where purpose in('Repack', 'Manufacture')")
|
|
||||||
erpnext.patches.v7_1.save_stock_settings
|
|
||||||
erpnext.patches.v7_0.repost_gle_for_pi_with_update_stock #2016-11-01
|
|
||||||
erpnext.patches.v7_1.add_account_user_role_for_timesheet
|
|
||||||
erpnext.patches.v7_0.set_base_amount_in_invoice_payment_table
|
|
||||||
erpnext.patches.v7_1.update_invoice_status
|
|
||||||
erpnext.patches.v7_0.po_status_issue_for_pr_return
|
|
||||||
erpnext.patches.v7_1.update_missing_salary_component_type
|
|
||||||
erpnext.patches.v7_1.rename_quality_inspection_field
|
|
||||||
erpnext.patches.v7_0.update_autoname_field
|
|
||||||
erpnext.patches.v7_1.update_bom_base_currency
|
|
||||||
erpnext.patches.v7_0.update_status_of_po_so
|
|
||||||
erpnext.patches.v7_1.set_budget_against_as_cost_center
|
|
||||||
erpnext.patches.v7_1.set_currency_exchange_date
|
|
||||||
erpnext.patches.v7_1.set_sales_person_status
|
|
||||||
erpnext.patches.v7_1.repost_stock_for_deleted_bins_for_merging_items
|
|
||||||
erpnext.patches.v7_2.update_website_for_variant
|
|
||||||
erpnext.patches.v7_2.update_assessment_modules
|
|
||||||
erpnext.patches.v7_2.update_doctype_status
|
|
||||||
erpnext.patches.v7_2.update_salary_slips
|
|
||||||
erpnext.patches.v7_2.delete_fleet_management_module_def
|
|
||||||
erpnext.patches.v7_2.contact_address_links
|
|
||||||
erpnext.patches.v7_2.mark_students_active
|
|
||||||
erpnext.patches.v7_2.set_null_value_to_fields
|
|
||||||
erpnext.patches.v7_2.update_guardian_name_in_student_master
|
|
||||||
erpnext.patches.v7_2.update_abbr_in_salary_slips
|
|
||||||
erpnext.patches.v7_2.rename_evaluation_criteria
|
|
||||||
erpnext.patches.v7_2.update_party_type
|
|
||||||
erpnext.patches.v7_2.setup_auto_close_settings
|
|
||||||
erpnext.patches.v7_2.empty_supplied_items_for_non_subcontracted
|
|
||||||
erpnext.patches.v7_2.arrear_leave_encashment_as_salary_component
|
|
||||||
erpnext.patches.v7_2.rename_att_date_attendance
|
|
||||||
erpnext.patches.v7_2.update_attendance_docstatus
|
|
||||||
erpnext.patches.v7_2.make_all_assessment_group
|
|
||||||
erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom
|
|
||||||
erpnext.patches.v8_0.addresses_linked_to_lead
|
|
||||||
execute:frappe.delete_doc('DocType', 'Purchase Common')
|
|
||||||
erpnext.patches.v8_0.update_stock_qty_value_in_purchase_invoice
|
|
||||||
erpnext.patches.v8_0.update_supplier_address_in_stock_entry
|
|
||||||
erpnext.patches.v8_0.rename_is_sample_item_to_allow_zero_valuation_rate
|
|
||||||
erpnext.patches.v8_0.set_null_to_serial_nos_for_disabled_sales_invoices
|
|
||||||
erpnext.patches.v8_0.enable_booking_asset_depreciation_automatically
|
|
||||||
erpnext.patches.v8_0.set_project_copied_from
|
|
||||||
erpnext.patches.v8_0.update_status_as_paid_for_completed_expense_claim
|
|
||||||
erpnext.patches.v7_2.stock_uom_in_selling
|
|
||||||
erpnext.patches.v8_0.revert_manufacturers_table_from_item
|
|
||||||
erpnext.patches.v8_0.disable_instructor_role
|
|
||||||
erpnext.patches.v8_0.merge_student_batch_and_student_group
|
|
||||||
erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017
|
|
||||||
erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding
|
|
||||||
erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice
|
|
||||||
erpnext.patches.v8_0.set_sales_invoice_serial_number_from_delivery_note
|
|
||||||
erpnext.patches.v8_0.delete_schools_depricated_doctypes
|
|
||||||
erpnext.patches.v8_0.update_customer_pos_id
|
|
||||||
erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
|
|
||||||
erpnext.patches.v8_0.delete_bin_indexes
|
|
||||||
erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory
|
|
||||||
erpnext.patches.v8_0.change_in_words_varchar_length
|
|
||||||
erpnext.patches.v8_0.update_stock_qty_value_in_bom_item
|
|
||||||
erpnext.patches.v8_0.update_sales_cost_in_project
|
|
||||||
erpnext.patches.v8_0.save_system_settings
|
|
||||||
erpnext.patches.v8_1.delete_deprecated_reports
|
|
||||||
erpnext.patches.v9_0.remove_subscription_module
|
|
||||||
erpnext.patches.v8_7.make_subscription_from_recurring_data
|
|
||||||
erpnext.patches.v8_1.setup_gst_india #2017-06-27
|
erpnext.patches.v8_1.setup_gst_india #2017-06-27
|
||||||
execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
|
|
||||||
erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account #16-08-2018
|
erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account #16-08-2018
|
||||||
erpnext.patches.v8_1.gst_fixes #2017-07-06
|
|
||||||
erpnext.patches.v8_0.update_production_orders
|
|
||||||
erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no
|
|
||||||
erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit
|
|
||||||
erpnext.patches.v8_1.add_hsn_sac_codes
|
|
||||||
erpnext.patches.v8_1.update_gst_state #17-07-2017
|
|
||||||
erpnext.patches.v8_1.removed_report_support_hours
|
|
||||||
erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
|
|
||||||
erpnext.patches.v8_3.set_restrict_to_domain_for_module_def
|
|
||||||
erpnext.patches.v8_1.update_expense_claim_status
|
|
||||||
erpnext.patches.v8_3.update_company_total_sales #2017-08-16
|
|
||||||
erpnext.patches.v8_4.make_scorecard_records
|
|
||||||
erpnext.patches.v8_1.set_delivery_date_in_so_item #2017-07-28
|
|
||||||
erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs
|
|
||||||
erpnext.patches.v8_5.remove_quotations_route_in_sidebar
|
|
||||||
erpnext.patches.v8_5.update_existing_data_in_project_type
|
|
||||||
erpnext.patches.v8_5.set_default_mode_of_payment
|
|
||||||
erpnext.patches.v8_5.update_customer_group_in_POS_profile
|
|
||||||
erpnext.patches.v8_6.update_timesheet_company_from_PO
|
|
||||||
erpnext.patches.v8_6.set_write_permission_for_quotation_for_sales_manager
|
|
||||||
erpnext.patches.v8_5.remove_project_type_property_setter
|
|
||||||
erpnext.patches.v8_7.sync_india_custom_fields
|
erpnext.patches.v8_7.sync_india_custom_fields
|
||||||
erpnext.patches.v8_7.fix_purchase_receipt_status
|
|
||||||
erpnext.patches.v8_6.rename_bom_update_tool
|
|
||||||
erpnext.patches.v8_9.add_setup_progress_actions #08-09-2017 #26-09-2017 #22-11-2017 #15-12-2017
|
|
||||||
erpnext.patches.v8_9.rename_company_sales_target_field
|
|
||||||
erpnext.patches.v8_8.set_bom_rate_as_per_uom
|
|
||||||
erpnext.patches.v8_8.add_new_fields_in_accounts_settings
|
|
||||||
erpnext.patches.v8_9.set_default_customer_group
|
|
||||||
erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts
|
|
||||||
erpnext.patches.v8_9.set_default_fields_in_variant_settings
|
|
||||||
erpnext.patches.v8_9.update_billing_gstin_for_indian_account
|
|
||||||
erpnext.patches.v8_9.set_member_party_type
|
|
||||||
erpnext.patches.v9_0.add_user_to_child_table_in_pos_profile
|
|
||||||
erpnext.patches.v9_0.set_schedule_date_for_material_request_and_purchase_order
|
|
||||||
erpnext.patches.v9_0.student_admission_childtable_migrate
|
|
||||||
erpnext.patches.v9_0.add_healthcare_domain
|
|
||||||
erpnext.patches.v9_0.set_variant_item_description
|
|
||||||
erpnext.patches.v9_0.set_uoms_in_variant_field
|
|
||||||
erpnext.patches.v9_0.copy_old_fees_field_data
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Program Fee")
|
|
||||||
erpnext.patches.v9_0.set_pos_profile_name
|
|
||||||
erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings
|
|
||||||
execute:frappe.delete_doc_if_exists("DocType", "Program Fee")
|
|
||||||
erpnext.patches.v8_10.change_default_customer_credit_days
|
|
||||||
erpnext.patches.v9_0.update_employee_loan_details
|
|
||||||
erpnext.patches.v9_2.delete_healthcare_domain_default_items
|
|
||||||
erpnext.patches.v9_1.create_issue_opportunity_type
|
|
||||||
erpnext.patches.v9_2.rename_translated_domains_in_en
|
|
||||||
erpnext.patches.v9_0.set_shipping_type_for_existing_shipping_rules
|
|
||||||
erpnext.patches.v9_0.update_multi_uom_fields_in_material_request
|
|
||||||
erpnext.patches.v9_2.repost_reserved_qty_for_production
|
|
||||||
erpnext.patches.v9_2.remove_company_from_patient
|
|
||||||
erpnext.patches.v9_2.set_item_name_in_production_order
|
|
||||||
erpnext.patches.v10_0.update_lft_rgt_for_employee
|
|
||||||
erpnext.patches.v9_2.rename_net_weight_in_item_master
|
|
||||||
erpnext.patches.v9_2.delete_process_payroll
|
|
||||||
erpnext.patches.v10_0.add_agriculture_domain
|
|
||||||
erpnext.patches.v10_0.add_non_profit_domain
|
|
||||||
erpnext.patches.v10_0.setup_vat_for_uae_and_saudi_arabia #2017-12-28
|
|
||||||
erpnext.patches.v10_0.set_primary_contact_for_customer
|
|
||||||
erpnext.patches.v10_0.copy_projects_renamed_fields
|
|
||||||
erpnext.patches.v10_0.enabled_regional_print_format_based_on_country
|
|
||||||
erpnext.patches.v10_0.update_asset_calculate_depreciation
|
|
||||||
erpnext.patches.v10_0.add_guardian_role_for_parent_portal
|
|
||||||
erpnext.patches.v10_0.set_numeric_ranges_in_template_if_blank
|
|
||||||
erpnext.patches.v10_0.update_reserved_qty_for_purchase_order
|
|
||||||
erpnext.patches.v10_0.fichier_des_ecritures_comptables_for_france
|
erpnext.patches.v10_0.fichier_des_ecritures_comptables_for_france
|
||||||
erpnext.patches.v10_0.update_assessment_plan
|
|
||||||
erpnext.patches.v10_0.update_assessment_result
|
|
||||||
erpnext.patches.v10_0.set_default_payment_terms_based_on_company
|
|
||||||
erpnext.patches.v10_0.update_sales_order_link_to_purchase_order
|
|
||||||
erpnext.patches.v10_0.rename_price_to_rate_in_pricing_rule
|
erpnext.patches.v10_0.rename_price_to_rate_in_pricing_rule
|
||||||
erpnext.patches.v10_0.set_currency_in_pricing_rule
|
erpnext.patches.v10_0.set_currency_in_pricing_rule
|
||||||
erpnext.patches.v10_0.set_b2c_limit
|
|
||||||
erpnext.patches.v10_0.update_translatable_fields
|
erpnext.patches.v10_0.update_translatable_fields
|
||||||
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
||||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
||||||
@@ -496,16 +21,6 @@ erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_
|
|||||||
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
||||||
erpnext.patches.v11_0.rename_duplicate_item_code_values
|
erpnext.patches.v11_0.rename_duplicate_item_code_values
|
||||||
erpnext.patches.v11_0.make_quality_inspection_template
|
erpnext.patches.v11_0.make_quality_inspection_template
|
||||||
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
|
|
||||||
erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
|
|
||||||
erpnext.patches.v10_0.update_territory_and_customer_group
|
|
||||||
erpnext.patches.v10_0.update_warehouse_address_details
|
|
||||||
erpnext.patches.v10_0.update_reserved_qty_for_purchase_order
|
|
||||||
erpnext.patches.v10_0.update_hub_connector_domain
|
|
||||||
erpnext.patches.v10_0.set_student_party_type
|
|
||||||
erpnext.patches.v10_0.update_project_in_sle
|
|
||||||
erpnext.patches.v10_0.fix_reserved_qty_for_sub_contract
|
|
||||||
erpnext.patches.v10_0.repost_requested_qty_for_non_stock_uom_items
|
|
||||||
erpnext.patches.v11_0.merge_land_unit_with_location
|
erpnext.patches.v11_0.merge_land_unit_with_location
|
||||||
erpnext.patches.v11_0.add_index_on_nestedset_doctypes
|
erpnext.patches.v11_0.add_index_on_nestedset_doctypes
|
||||||
erpnext.patches.v11_0.remove_modules_setup_page
|
erpnext.patches.v11_0.remove_modules_setup_page
|
||||||
@@ -514,7 +29,6 @@ erpnext.patches.v11_0.update_department_lft_rgt
|
|||||||
erpnext.patches.v11_0.add_default_email_template_for_leave
|
erpnext.patches.v11_0.add_default_email_template_for_leave
|
||||||
erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018
|
erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018
|
||||||
erpnext.patches.v11_0.uom_conversion_data #30-06-2018
|
erpnext.patches.v11_0.uom_conversion_data #30-06-2018
|
||||||
erpnext.patches.v10_0.taxes_issue_with_pos
|
|
||||||
erpnext.patches.v11_0.update_account_type_in_party_type
|
erpnext.patches.v11_0.update_account_type_in_party_type
|
||||||
erpnext.patches.v11_0.rename_healthcare_doctype_and_fields
|
erpnext.patches.v11_0.rename_healthcare_doctype_and_fields
|
||||||
erpnext.patches.v11_0.rename_supplier_type_to_supplier_group
|
erpnext.patches.v11_0.rename_supplier_type_to_supplier_group
|
||||||
@@ -522,8 +36,6 @@ erpnext.patches.v10_1.transfer_subscription_to_auto_repeat
|
|||||||
erpnext.patches.v11_0.update_brand_in_item_price
|
erpnext.patches.v11_0.update_brand_in_item_price
|
||||||
erpnext.patches.v11_0.create_default_success_action
|
erpnext.patches.v11_0.create_default_success_action
|
||||||
erpnext.patches.v11_0.add_healthcare_service_unit_tree_root
|
erpnext.patches.v11_0.add_healthcare_service_unit_tree_root
|
||||||
erpnext.patches.v10_0.set_qty_in_transactions_based_on_serial_no_input
|
|
||||||
erpnext.patches.v10_0.show_leaves_of_all_department_members_in_calendar
|
|
||||||
erpnext.patches.v11_0.rename_field_max_days_allowed
|
erpnext.patches.v11_0.rename_field_max_days_allowed
|
||||||
erpnext.patches.v11_0.create_salary_structure_assignments
|
erpnext.patches.v11_0.create_salary_structure_assignments
|
||||||
erpnext.patches.v11_0.rename_health_insurance
|
erpnext.patches.v11_0.rename_health_insurance
|
||||||
@@ -536,7 +48,6 @@ erpnext.patches.v11_0.move_item_defaults_to_child_table_for_multicompany #02-07-
|
|||||||
erpnext.patches.v11_0.refactor_erpnext_shopify #2018-09-07
|
erpnext.patches.v11_0.refactor_erpnext_shopify #2018-09-07
|
||||||
erpnext.patches.v11_0.rename_overproduction_percent_field
|
erpnext.patches.v11_0.rename_overproduction_percent_field
|
||||||
erpnext.patches.v11_0.update_backflush_subcontract_rm_based_on_bom
|
erpnext.patches.v11_0.update_backflush_subcontract_rm_based_on_bom
|
||||||
erpnext.patches.v10_0.update_status_in_purchase_receipt
|
|
||||||
erpnext.patches.v11_0.inter_state_field_for_gst
|
erpnext.patches.v11_0.inter_state_field_for_gst
|
||||||
erpnext.patches.v11_0.rename_members_with_naming_series #04-06-2018
|
erpnext.patches.v11_0.rename_members_with_naming_series #04-06-2018
|
||||||
erpnext.patches.v11_0.set_update_field_and_value_in_workflow_state
|
erpnext.patches.v11_0.set_update_field_and_value_in_workflow_state
|
||||||
@@ -550,13 +61,10 @@ erpnext.patches.v11_0.skip_user_permission_check_for_department
|
|||||||
erpnext.patches.v11_0.set_department_for_doctypes
|
erpnext.patches.v11_0.set_department_for_doctypes
|
||||||
erpnext.patches.v11_0.update_allow_transfer_for_manufacture
|
erpnext.patches.v11_0.update_allow_transfer_for_manufacture
|
||||||
erpnext.patches.v11_0.add_item_group_defaults
|
erpnext.patches.v11_0.add_item_group_defaults
|
||||||
erpnext.patches.v10_0.update_address_template_for_india
|
|
||||||
erpnext.patches.v11_0.add_expense_claim_default_account
|
erpnext.patches.v11_0.add_expense_claim_default_account
|
||||||
execute:frappe.delete_doc("Page", "hub")
|
execute:frappe.delete_doc("Page", "hub")
|
||||||
erpnext.patches.v11_0.reset_publish_in_hub_for_all_items
|
erpnext.patches.v11_0.reset_publish_in_hub_for_all_items
|
||||||
erpnext.patches.v11_0.update_hub_url # 2018-08-31 # 2018-09-03
|
erpnext.patches.v11_0.update_hub_url # 2018-08-31 # 2018-09-03
|
||||||
erpnext.patches.v10_0.set_discount_amount
|
|
||||||
erpnext.patches.v10_0.recalculate_gross_margin_for_project
|
|
||||||
erpnext.patches.v11_0.make_job_card
|
erpnext.patches.v11_0.make_job_card
|
||||||
erpnext.patches.v11_0.redesign_healthcare_billing_work_flow
|
erpnext.patches.v11_0.redesign_healthcare_billing_work_flow
|
||||||
erpnext.patches.v10_0.delete_hub_documents # 12-08-2018
|
erpnext.patches.v10_0.delete_hub_documents # 12-08-2018
|
||||||
@@ -570,9 +78,6 @@ execute:frappe.delete_doc_if_exists("Page", "stock-analytics")
|
|||||||
execute:frappe.delete_doc_if_exists("Page", "production-analytics")
|
execute:frappe.delete_doc_if_exists("Page", "production-analytics")
|
||||||
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01 #2019-04-26 #2019-05-03
|
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01 #2019-04-26 #2019-05-03
|
||||||
erpnext.patches.v11_0.drop_column_max_days_allowed
|
erpnext.patches.v11_0.drop_column_max_days_allowed
|
||||||
erpnext.patches.v10_0.update_user_image_in_employee
|
|
||||||
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
|
|
||||||
erpnext.patches.v10_0.allow_operators_in_supplier_scorecard
|
|
||||||
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
|
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
|
||||||
erpnext.patches.v11_0.update_delivery_trip_status
|
erpnext.patches.v11_0.update_delivery_trip_status
|
||||||
erpnext.patches.v11_0.set_missing_gst_hsn_code
|
erpnext.patches.v11_0.set_missing_gst_hsn_code
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
from erpnext.stock.stock_balance import set_stock_balance_as_per_serial_no
|
|
||||||
frappe.db.auto_commit_on_many_writes = 1
|
|
||||||
|
|
||||||
set_stock_balance_as_per_serial_no()
|
|
||||||
|
|
||||||
frappe.db.auto_commit_on_many_writes = 0
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
domain = 'Agriculture'
|
|
||||||
if not frappe.db.exists('Domain', domain):
|
|
||||||
frappe.get_doc({
|
|
||||||
'doctype': 'Domain',
|
|
||||||
'domain': domain
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
# create guardian role
|
|
||||||
if not frappe.get_value('Role', dict(role_name='Guardian')):
|
|
||||||
frappe.get_doc({
|
|
||||||
'doctype': 'Role',
|
|
||||||
'role_name': 'Guardian',
|
|
||||||
'desk_access': 0,
|
|
||||||
'restrict_to_domain': 'Education'
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
# set guardian roles in already created users
|
|
||||||
if frappe.db.exists("Doctype", "Guardian"):
|
|
||||||
for user in frappe.db.sql_list("""select u.name from `tabUser` u , `tabGuardian` g where g.email_address = u.name"""):
|
|
||||||
user = frappe.get_doc('User', user)
|
|
||||||
user.flags.ignore_validate = True
|
|
||||||
user.flags.ignore_mandatory = True
|
|
||||||
user.save()
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
domain = 'Non Profit'
|
|
||||||
if not frappe.db.exists('Domain', domain):
|
|
||||||
frappe.get_doc({
|
|
||||||
'doctype': 'Domain',
|
|
||||||
'domain': domain
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
frappe.get_doc({
|
|
||||||
'doctype': 'Role',
|
|
||||||
'role_name': 'Non Profit Portal User',
|
|
||||||
'desk_access': 0,
|
|
||||||
'restrict_to_domain': domain
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Copyright (c) 2019, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_criteria')
|
|
||||||
frappe.reload_doc('buying', 'doctype', 'supplier_scorecard_scoring_criteria')
|
|
||||||
frappe.reload_doc('buying', 'doctype', 'supplier_scorecard')
|
|
||||||
|
|
||||||
for criteria in frappe.get_all('Supplier Scorecard Criteria', fields=['name', 'formula'], limit_page_length=None):
|
|
||||||
frappe.db.set_value('Supplier Scorecard Criteria', criteria.name,
|
|
||||||
'formula', criteria.formula.replace('<','<').replace('>','>'))
|
|
||||||
|
|
||||||
for criteria in frappe.get_all('Supplier Scorecard Scoring Criteria', fields=['name', 'formula'], limit_page_length=None):
|
|
||||||
if criteria.formula: # not mandatory
|
|
||||||
frappe.db.set_value('Supplier Scorecard Scoring Criteria', criteria.name,
|
|
||||||
'formula', criteria.formula.replace('<','<').replace('>','>'))
|
|
||||||
|
|
||||||
for sc in frappe.get_all('Supplier Scorecard', fields=['name', 'weighting_function'], limit_page_length=None):
|
|
||||||
frappe.db.set_value('Supplier Scorecard', sc.name, 'weighting_function',
|
|
||||||
sc.weighting_function.replace('<','<').replace('>','>'))
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe.model.utils.rename_field import rename_field
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
""" copy data from old fields to new """
|
|
||||||
frappe.reload_doc("projects", "doctype", "project")
|
|
||||||
|
|
||||||
if frappe.db.has_column('Project', 'total_sales_cost'):
|
|
||||||
rename_field('Project', "total_sales_cost", "total_sales_amount")
|
|
||||||
|
|
||||||
if frappe.db.has_column('Project', 'total_billing_amount'):
|
|
||||||
rename_field('Project', "total_billing_amount", "total_billable_amount")
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
print_format_mapper = {
|
|
||||||
'India': ['GST POS Invoice', 'GST Tax Invoice'],
|
|
||||||
'Saudi Arabia': ['Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice'],
|
|
||||||
'United Arab Emirates': ['Simplified Tax Invoice', 'Detailed Tax Invoice', 'Tax Invoice']
|
|
||||||
}
|
|
||||||
|
|
||||||
frappe.db.sql(""" update `tabPrint Format` set disabled = 1 where name
|
|
||||||
in ('GST POS Invoice', 'GST Tax Invoice', 'Simplified Tax Invoice', 'Detailed Tax Invoice')""")
|
|
||||||
|
|
||||||
for d in frappe.get_all('Company', fields = ["country"],
|
|
||||||
filters={'country': ('in', ['India', 'Saudi Arabia', 'United Arab Emirates'])}):
|
|
||||||
if print_format_mapper.get(d.country):
|
|
||||||
print_formats = print_format_mapper.get(d.country)
|
|
||||||
frappe.db.sql(""" update `tabPrint Format` set disabled = 0
|
|
||||||
where name in (%s)""" % ", ".join(["%s"]*len(print_formats)), tuple(print_formats))
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from erpnext.stock.utils import get_bin
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("stock", "doctype", "bin")
|
|
||||||
frappe.reload_doc("buying", "doctype", "purchase_order_item_supplied")
|
|
||||||
for d in frappe.db.sql("""
|
|
||||||
select distinct rm_item_code, reserve_warehouse
|
|
||||||
from `tabPurchase Order Item Supplied`
|
|
||||||
where docstatus=1 and reserve_warehouse is not null and reserve_warehouse != ''"""):
|
|
||||||
|
|
||||||
try:
|
|
||||||
bin_doc = get_bin(d[0], d[1])
|
|
||||||
bin_doc.update_reserved_qty_for_sub_contracting()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for d in frappe.db.sql("""select distinct item_code, source_warehouse
|
|
||||||
from `tabWork Order Item`
|
|
||||||
where docstatus=1 and transferred_qty > required_qty
|
|
||||||
and source_warehouse is not null and source_warehouse != ''""", as_list=1):
|
|
||||||
|
|
||||||
try:
|
|
||||||
bin_doc = get_bin(d[0], d[1])
|
|
||||||
bin_doc.update_reserved_qty_for_production()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc('projects', 'doctype', 'project')
|
|
||||||
for d in frappe.db.sql(""" select name from `tabProject` where
|
|
||||||
ifnull(total_consumed_material_cost, 0 ) > 0 and ifnull(total_billed_amount, 0) > 0""", as_dict=1):
|
|
||||||
doc = frappe.get_doc("Project", d.name)
|
|
||||||
doc.calculate_gross_margin()
|
|
||||||
doc.db_set('gross_margin', doc.gross_margin)
|
|
||||||
doc.db_set('per_gross_margin', doc.per_gross_margin)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
# rename the School module as Education
|
|
||||||
|
|
||||||
# rename the school module
|
|
||||||
if frappe.db.exists('Module Def', 'Schools') and not frappe.db.exists('Module Def', 'Education'):
|
|
||||||
frappe.rename_doc("Module Def", "Schools", "Education")
|
|
||||||
|
|
||||||
# delete the school module
|
|
||||||
if frappe.db.exists('Module Def', 'Schools') and frappe.db.exists('Module Def', 'Education'):
|
|
||||||
frappe.db.sql("""delete from `tabModule Def` where module_name = 'Schools'""")
|
|
||||||
|
|
||||||
|
|
||||||
# rename "School Settings" to the "Education Settings
|
|
||||||
if frappe.db.exists('DocType', 'School Settings'):
|
|
||||||
frappe.rename_doc("DocType", "School Settings", "Education Settings", force=True)
|
|
||||||
frappe.reload_doc("education", "doctype", "education_settings")
|
|
||||||
|
|
||||||
# delete the discussion web form if exists
|
|
||||||
if frappe.db.exists('Web Form', 'Discussion'):
|
|
||||||
frappe.db.sql("""delete from `tabWeb Form` where name = 'discussion'""")
|
|
||||||
|
|
||||||
# rename the select option field from "School Bus" to "Institute's Bus"
|
|
||||||
frappe.reload_doc("education", "doctype", "Program Enrollment")
|
|
||||||
if "mode_of_transportation" in frappe.db.get_table_columns("Program Enrollment"):
|
|
||||||
frappe.db.sql("""update `tabProgram Enrollment` set mode_of_transportation = "Institute's Bus"
|
|
||||||
where mode_of_transportation = "School Bus" """)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe, erpnext
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
for company in frappe.get_all("Company"):
|
|
||||||
if not erpnext.is_perpetual_inventory_enabled(company.name):
|
|
||||||
continue
|
|
||||||
|
|
||||||
acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto") or "1900-01-01"
|
|
||||||
pr_with_rejected_warehouse = frappe.db.sql("""
|
|
||||||
select pr.name
|
|
||||||
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
|
|
||||||
where pr.name = pr_item.parent
|
|
||||||
and pr.posting_date > %s
|
|
||||||
and pr.docstatus=1
|
|
||||||
and pr.company = %s
|
|
||||||
and pr_item.rejected_qty > 0
|
|
||||||
""", (acc_frozen_upto, company.name), as_dict=1)
|
|
||||||
|
|
||||||
for d in pr_with_rejected_warehouse:
|
|
||||||
doc = frappe.get_doc("Purchase Receipt", d.name)
|
|
||||||
|
|
||||||
doc.docstatus = 2
|
|
||||||
doc.make_gl_entries_on_cancel()
|
|
||||||
|
|
||||||
|
|
||||||
# update gl entries for submit state of PR
|
|
||||||
doc.docstatus = 1
|
|
||||||
doc.make_gl_entries()
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright (c) 2019, Web Notes Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
|
|
||||||
|
|
||||||
count=0
|
|
||||||
for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse
|
|
||||||
from `tabMaterial Request Item` where docstatus = 1 and stock_uom<>uom"""):
|
|
||||||
try:
|
|
||||||
count += 1
|
|
||||||
update_bin_qty(item_code, warehouse, {
|
|
||||||
"indented_qty": get_indented_qty(item_code, warehouse),
|
|
||||||
})
|
|
||||||
if count % 200 == 0:
|
|
||||||
frappe.db.commit()
|
|
||||||
except:
|
|
||||||
frappe.db.rollback()
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
serialised_items = [d.name for d in frappe.get_all("Item", filters={"has_serial_no": 1})]
|
|
||||||
|
|
||||||
if not serialised_items:
|
|
||||||
return
|
|
||||||
|
|
||||||
for dt in ["Stock Entry Detail", "Purchase Receipt Item", "Purchase Invoice Item"]:
|
|
||||||
cond = ""
|
|
||||||
if dt=="Purchase Invoice Item":
|
|
||||||
cond = """ and parent in (select name from `tabPurchase Invoice`
|
|
||||||
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.parent and update_stock=1)"""
|
|
||||||
|
|
||||||
item_rows = frappe.db.sql("""
|
|
||||||
select name
|
|
||||||
from `tab{0}`
|
|
||||||
where conversion_factor != 1
|
|
||||||
and docstatus = 1
|
|
||||||
and ifnull(serial_no, '') = ''
|
|
||||||
and item_code in ({1})
|
|
||||||
{2}
|
|
||||||
""".format(dt, ', '.join(['%s']*len(serialised_items)), cond), tuple(serialised_items))
|
|
||||||
|
|
||||||
if item_rows:
|
|
||||||
sle_serial_nos = dict(frappe.db.sql("""
|
|
||||||
select voucher_detail_no, serial_no
|
|
||||||
from `tabStock Ledger Entry`
|
|
||||||
where ifnull(serial_no, '') != ''
|
|
||||||
and voucher_detail_no in (%s)
|
|
||||||
""".format(', '.join(['%s']*len(item_rows))),
|
|
||||||
tuple([d[0] for d in item_rows])))
|
|
||||||
|
|
||||||
batch_size = 100
|
|
||||||
for i in range(0, len(item_rows), batch_size):
|
|
||||||
batch_item_rows = item_rows[i:i + batch_size]
|
|
||||||
when_then = []
|
|
||||||
for item_row in batch_item_rows:
|
|
||||||
|
|
||||||
when_then.append('WHEN `name` = "{row_name}" THEN "{value}"'.format(
|
|
||||||
row_name=item_row[0],
|
|
||||||
value=sle_serial_nos.get(item_row[0])))
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update
|
|
||||||
`tab{doctype}`
|
|
||||||
set
|
|
||||||
serial_no = CASE {when_then_cond} ELSE `serial_no` END
|
|
||||||
""".format(
|
|
||||||
doctype = dt,
|
|
||||||
when_then_cond=" ".join(when_then)
|
|
||||||
))
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("regional", "doctype", "gst_settings")
|
|
||||||
frappe.reload_doc("accounts", "doctype", "gst_account")
|
|
||||||
gst_settings = frappe.get_doc("GST Settings")
|
|
||||||
gst_settings.b2c_limit = 250000
|
|
||||||
gst_settings.save()
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from erpnext.patches.v8_10.change_default_customer_credit_days import make_payment_term, make_template
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
for dt in ("Company", "Customer Group"):
|
|
||||||
frappe.reload_doc("setup", "doctype", frappe.scrub(dt))
|
|
||||||
|
|
||||||
credit_records = frappe.db.sql("""
|
|
||||||
SELECT DISTINCT `credit_days`, `credit_days_based_on`, `name`
|
|
||||||
from `tab{0}`
|
|
||||||
where
|
|
||||||
((credit_days_based_on='Fixed Days' or credit_days_based_on is null) and credit_days is not null)
|
|
||||||
or credit_days_based_on='Last Day of the Next Month'
|
|
||||||
""".format(dt), as_dict=1)
|
|
||||||
|
|
||||||
for d in credit_records:
|
|
||||||
template = create_payment_terms_template(d)
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update `tab{0}`
|
|
||||||
set `payment_terms` = %s
|
|
||||||
where name = %s
|
|
||||||
""".format(dt), (template.name, d.name))
|
|
||||||
|
|
||||||
def create_payment_terms_template(data):
|
|
||||||
if data.credit_days_based_on == "Fixed Days":
|
|
||||||
pyt_template_name = 'Default Payment Term - N{0}'.format(data.credit_days)
|
|
||||||
else:
|
|
||||||
pyt_template_name = 'Default Payment Term - EO2M'
|
|
||||||
|
|
||||||
if not frappe.db.exists("Payment Terms Template", pyt_template_name):
|
|
||||||
payment_term = make_payment_term(data.credit_days, data.credit_days_based_on)
|
|
||||||
template = make_template(payment_term)
|
|
||||||
else:
|
|
||||||
template = frappe.get_doc("Payment Terms Template", pyt_template_name)
|
|
||||||
return template
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("accounts", "doctype", "sales_invoice_item")
|
|
||||||
frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_item')
|
|
||||||
frappe.reload_doc('buying', 'doctype', 'purchase_order_item')
|
|
||||||
frappe.reload_doc('buying', 'doctype', 'supplier_quotation_item')
|
|
||||||
frappe.reload_doc('selling', 'doctype', 'sales_order_item')
|
|
||||||
frappe.reload_doc('selling', 'doctype', 'quotation_item')
|
|
||||||
frappe.reload_doc('stock', 'doctype', 'delivery_note_item')
|
|
||||||
frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item')
|
|
||||||
|
|
||||||
selling_doctypes = ["Sales Order Item", "Sales Invoice Item", "Delivery Note Item", "Quotation Item"]
|
|
||||||
buying_doctypes = ["Purchase Order Item", "Purchase Invoice Item", "Purchase Receipt Item", "Supplier Quotation Item"]
|
|
||||||
|
|
||||||
for doctype in selling_doctypes:
|
|
||||||
frappe.db.sql('''
|
|
||||||
UPDATE
|
|
||||||
`tab%s`
|
|
||||||
SET
|
|
||||||
discount_amount = if(rate_with_margin > 0, rate_with_margin, price_list_rate) * discount_percentage / 100
|
|
||||||
WHERE
|
|
||||||
discount_percentage > 0
|
|
||||||
''' % (doctype))
|
|
||||||
for doctype in buying_doctypes:
|
|
||||||
frappe.db.sql('''
|
|
||||||
UPDATE
|
|
||||||
`tab%s`
|
|
||||||
SET
|
|
||||||
discount_amount = price_list_rate * discount_percentage / 100
|
|
||||||
WHERE
|
|
||||||
discount_percentage > 0
|
|
||||||
''' % (doctype))
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
item_numeric_attributes = frappe.db.sql("""
|
|
||||||
select name, numeric_values, from_range, to_range, increment
|
|
||||||
from `tabItem Attribute`
|
|
||||||
where numeric_values = 1
|
|
||||||
""", as_dict=1)
|
|
||||||
|
|
||||||
for d in item_numeric_attributes:
|
|
||||||
frappe.db.sql("""
|
|
||||||
update `tabItem Variant Attribute`
|
|
||||||
set
|
|
||||||
from_range = CASE
|
|
||||||
WHEN from_range = 0 THEN %(from_range)s
|
|
||||||
ELSE from_range
|
|
||||||
END,
|
|
||||||
to_range = CASE
|
|
||||||
WHEN to_range = 0 THEN %(to_range)s
|
|
||||||
ELSE to_range
|
|
||||||
END,
|
|
||||||
increment = CASE
|
|
||||||
WHEN increment = 0 THEN %(increment)s
|
|
||||||
ELSE increment
|
|
||||||
END,
|
|
||||||
numeric_values = %(numeric_values)s
|
|
||||||
where
|
|
||||||
attribute = %(name)s
|
|
||||||
and exists(select name from tabItem
|
|
||||||
where name=`tabItem Variant Attribute`.parent and has_variants=1)
|
|
||||||
""", d)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doctype('Customer')
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update
|
|
||||||
`tabCustomer`, (
|
|
||||||
select `tabContact`.name, `tabContact`.mobile_no, `tabContact`.email_id,
|
|
||||||
`tabDynamic Link`.link_name from `tabContact`, `tabDynamic Link`
|
|
||||||
where `tabContact`.name = `tabDynamic Link`.parent and
|
|
||||||
`tabDynamic Link`.link_doctype = 'Customer' and `tabContact`.is_primary_contact = 1
|
|
||||||
) as contact
|
|
||||||
set
|
|
||||||
`tabCustomer`.customer_primary_contact = contact.name,
|
|
||||||
`tabCustomer`.mobile_no = contact.mobile_no, `tabCustomer`.email_id = contact.email_id
|
|
||||||
where `tabCustomer`.name = contact.link_name""")
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("stock", "doctype", "stock_settings")
|
|
||||||
|
|
||||||
ss = frappe.get_doc("Stock Settings")
|
|
||||||
ss.set_qty_in_transactions_based_on_serial_no_input = 1
|
|
||||||
|
|
||||||
if ss.default_warehouse \
|
|
||||||
and not frappe.db.exists("Warehouse", ss.default_warehouse):
|
|
||||||
ss.default_warehouse = None
|
|
||||||
|
|
||||||
if ss.stock_uom and not frappe.db.exists("UOM", ss.stock_uom):
|
|
||||||
ss.stock_uom = None
|
|
||||||
|
|
||||||
ss.flags.ignore_mandatory = True
|
|
||||||
ss.save()
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
if not frappe.db.exists("Party Type", "Student"):
|
|
||||||
party = frappe.new_doc("Party Type")
|
|
||||||
party.party_type = "Student"
|
|
||||||
party.save()
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from erpnext.setup.doctype.company.company import install_country_fixtures
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("accounts", "doctype", "account")
|
|
||||||
frappe.reload_doc("accounts", "doctype", "payment_schedule")
|
|
||||||
for d in frappe.get_all('Company',
|
|
||||||
filters={'country': ('in', ['Saudi Arabia', 'United Arab Emirates'])}):
|
|
||||||
install_country_fixtures(d.name)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("hr", "doctype", "hr_settings")
|
|
||||||
frappe.db.set_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar", 1)
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
for d in frappe.get_all('Sales Invoice', fields=["name"],
|
|
||||||
filters = {'is_pos':1, 'docstatus': 1, 'creation': ('>', '2018-04-23')}):
|
|
||||||
doc = frappe.get_doc('Sales Invoice', d.name)
|
|
||||||
if (not doc.taxes and doc.taxes_and_charges and doc.pos_profile and doc.outstanding_amount != 0 and
|
|
||||||
frappe.db.get_value('POS Profile', doc.pos_profile, 'taxes_and_charges', cache=True) == doc.taxes_and_charges):
|
|
||||||
|
|
||||||
doc.append_taxes_from_master()
|
|
||||||
doc.calculate_taxes_and_totals()
|
|
||||||
for d in doc.taxes:
|
|
||||||
d.db_update()
|
|
||||||
|
|
||||||
doc.db_update()
|
|
||||||
|
|
||||||
delete_gle_for_voucher(doc.name)
|
|
||||||
doc.make_gl_entries()
|
|
||||||
|
|
||||||
def delete_gle_for_voucher(voucher_no):
|
|
||||||
frappe.db.sql("""delete from `tabGL Entry` where voucher_no = %(voucher_no)s""",
|
|
||||||
{'voucher_no': voucher_no})
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from erpnext.regional.address_template.setup import set_up_address_templates
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
|
|
||||||
address_template = frappe.db.get_value('Address Template', 'India', 'template')
|
|
||||||
if not address_template or "gstin" not in address_template:
|
|
||||||
set_up_address_templates(default_country='India')
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc('education', 'doctype', 'assessment_plan')
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
UPDATE `tabAssessment Plan` as ap
|
|
||||||
INNER JOIN `tabStudent Group` as sg ON sg.name = ap.student_group
|
|
||||||
SET ap.academic_term = sg.academic_term,
|
|
||||||
ap.academic_year = sg.academic_year,
|
|
||||||
ap.program = sg.program
|
|
||||||
WHERE ap.docstatus = 1
|
|
||||||
""")
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc('education', 'doctype', 'assessment_result')
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
UPDATE `tabAssessment Result` AS ar
|
|
||||||
INNER JOIN `tabAssessment Plan` AS ap ON ap.name = ar.assessment_plan
|
|
||||||
SET ar.academic_term = ap.academic_term,
|
|
||||||
ar.academic_year = ap.academic_year,
|
|
||||||
ar.program = ap.program,
|
|
||||||
ar.course = ap.course,
|
|
||||||
ar.assessment_group = ap.assessment_group,
|
|
||||||
ar.student_group = ap.student_group
|
|
||||||
WHERE ap.docstatus = 1
|
|
||||||
""")
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc('assets', 'doctype', 'asset')
|
|
||||||
frappe.reload_doc('assets', 'doctype', 'depreciation_schedule')
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update tabAsset a
|
|
||||||
set calculate_depreciation = 1
|
|
||||||
where exists(select ds.name from `tabDepreciation Schedule` ds where ds.parent=a.name)
|
|
||||||
""")
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
if frappe.db.table_exists("Data Migration Connector"):
|
|
||||||
frappe.db.sql("""
|
|
||||||
UPDATE `tabData Migration Connector`
|
|
||||||
SET hostname = 'https://hubmarket.org'
|
|
||||||
WHERE connector_name = 'Hub Connector'
|
|
||||||
""")
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe.utils.nestedset import rebuild_tree
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
""" assign lft and rgt appropriately """
|
|
||||||
frappe.reload_doc("hr", "doctype", "employee")
|
|
||||||
|
|
||||||
rebuild_tree("Employee", "reports_to")
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
for doctype in ['Sales Invoice', 'Delivery Note', 'Stock Entry']:
|
|
||||||
frappe.db.sql(""" update
|
|
||||||
`tabStock Ledger Entry` sle, `tab{0}` parent_doc
|
|
||||||
set
|
|
||||||
sle.project = parent_doc.project
|
|
||||||
where
|
|
||||||
sle.voucher_no = parent_doc.name and sle.voucher_type = %s and sle.project is null
|
|
||||||
and parent_doc.project is not null and parent_doc.project != ''""".format(doctype), doctype)
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from erpnext.stock.utils import get_bin
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
po_item = list(frappe.db.sql(("""
|
|
||||||
select distinct po.name as poname, poitem.rm_item_code as rm_item_code, po.company
|
|
||||||
from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitem
|
|
||||||
where po.name = poitem.parent
|
|
||||||
and po.is_subcontracted = "Yes"
|
|
||||||
and po.docstatus = 1"""), as_dict=1))
|
|
||||||
if not po_item:
|
|
||||||
return
|
|
||||||
|
|
||||||
frappe.reload_doc("stock", "doctype", "bin")
|
|
||||||
frappe.reload_doc("buying", "doctype", "purchase_order_item_supplied")
|
|
||||||
company_warehouse = frappe._dict(frappe.db.sql("""select company, min(name) from `tabWarehouse`
|
|
||||||
where is_group = 0 group by company"""))
|
|
||||||
|
|
||||||
items = list(set([d.rm_item_code for d in po_item]))
|
|
||||||
item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse
|
|
||||||
from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
|
|
||||||
|
|
||||||
# Update reserved warehouse
|
|
||||||
for item in po_item:
|
|
||||||
reserve_warehouse = get_warehouse(item.rm_item_code, item.company, company_warehouse, item_wh)
|
|
||||||
frappe.db.sql("""update `tabPurchase Order Item Supplied`
|
|
||||||
set reserve_warehouse = %s
|
|
||||||
where parent = %s and rm_item_code = %s
|
|
||||||
""", (reserve_warehouse, item["poname"], item["rm_item_code"]))
|
|
||||||
|
|
||||||
# Update bin
|
|
||||||
item_wh_bin = frappe.db.sql(("""
|
|
||||||
select distinct poitemsup.rm_item_code as rm_item_code,
|
|
||||||
poitemsup.reserve_warehouse as reserve_warehouse
|
|
||||||
from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup
|
|
||||||
where po.name = poitemsup.parent
|
|
||||||
and po.is_subcontracted = "Yes"
|
|
||||||
and po.docstatus = 1"""), as_dict=1)
|
|
||||||
for d in item_wh_bin:
|
|
||||||
try:
|
|
||||||
stock_bin = get_bin(d["rm_item_code"], d["reserve_warehouse"])
|
|
||||||
stock_bin.update_reserved_qty_for_sub_contracting()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_warehouse(item_code, company, company_warehouse, item_wh):
|
|
||||||
reserve_warehouse = item_wh.get(item_code)
|
|
||||||
if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != company:
|
|
||||||
reserve_warehouse = None
|
|
||||||
if not reserve_warehouse:
|
|
||||||
reserve_warehouse = company_warehouse.get(company)
|
|
||||||
return reserve_warehouse
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("buying", "doctype", "supplier_quotation_item")
|
|
||||||
|
|
||||||
for doctype in ['Purchase Order','Supplier Quotation']:
|
|
||||||
frappe.db.sql("""
|
|
||||||
Update
|
|
||||||
`tab{doctype} Item`, `tabMaterial Request Item`
|
|
||||||
set
|
|
||||||
`tab{doctype} Item`.sales_order = `tabMaterial Request Item`.sales_order
|
|
||||||
where
|
|
||||||
`tab{doctype} Item`.material_request= `tabMaterial Request Item`.parent
|
|
||||||
and `tab{doctype} Item`.material_request_item = `tabMaterial Request Item`.name
|
|
||||||
and `tabMaterial Request Item`.sales_order is not null""".format(doctype=doctype))
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# Copyright (c) 2017, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
|
|
||||||
|
|
||||||
# update the sales order item in the material request
|
|
||||||
frappe.reload_doc('stock', 'doctype', 'material_request_item')
|
|
||||||
frappe.db.sql('''update `tabMaterial Request Item` mri, `tabSales Order Item` soi
|
|
||||||
set mri.sales_order_item = soi.name
|
|
||||||
where ifnull(mri.sales_order, "")!="" and soi.parent=mri.sales_order
|
|
||||||
and soi.item_code=mri.item_code and mri.docstatus=1
|
|
||||||
''')
|
|
||||||
|
|
||||||
# update the sales order item in the purchase order
|
|
||||||
frappe.db.sql('''update `tabPurchase Order Item` poi, `tabSales Order Item` soi
|
|
||||||
set poi.sales_order_item = soi.name
|
|
||||||
where ifnull(poi.sales_order, "")!="" and soi.parent=poi.sales_order
|
|
||||||
and soi.item_code=poi.item_code and poi.docstatus = 1
|
|
||||||
''')
|
|
||||||
|
|
||||||
# Update the status in material request and sales order
|
|
||||||
po_list = frappe.db.sql('''
|
|
||||||
select parent from `tabPurchase Order Item` where ifnull(material_request, "")!="" and
|
|
||||||
ifnull(sales_order, "")!="" and docstatus=1
|
|
||||||
''',as_dict=1)
|
|
||||||
|
|
||||||
for po in list(set([d.get("parent") for d in po_list if d.get("parent")])):
|
|
||||||
try:
|
|
||||||
po_doc = frappe.get_doc("Purchase Order", po)
|
|
||||||
|
|
||||||
# update the so in the status updater
|
|
||||||
po_doc.update_status_updater()
|
|
||||||
po_doc.update_qty(update_modified=False)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("stock", "doctype", "purchase_receipt")
|
|
||||||
frappe.db.sql('''
|
|
||||||
UPDATE `tabPurchase Receipt` SET status = "Completed" WHERE per_billed = 100 AND docstatus = 1
|
|
||||||
''')
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe.model.rename_doc import get_fetch_fields
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"]
|
|
||||||
customers = frappe.get_all('Customer', fields=["name", "customer_group"])
|
|
||||||
customer_group_fetch = get_fetch_fields('Customer', 'Customer Group', ignore_doctypes)
|
|
||||||
|
|
||||||
batch_size = 1000
|
|
||||||
for i in range(0, len(customers), batch_size):
|
|
||||||
batch_customers = customers[i:i + batch_size]
|
|
||||||
for d in customer_group_fetch:
|
|
||||||
when_then = []
|
|
||||||
for customer in batch_customers:
|
|
||||||
value = frappe.db.escape(frappe.as_unicode(customer.get("customer_group")))
|
|
||||||
|
|
||||||
when_then.append('''
|
|
||||||
WHEN `%s` = %s and %s != %s
|
|
||||||
THEN %s
|
|
||||||
'''%(d["master_fieldname"], frappe.db.escape(frappe.as_unicode(customer.name)),
|
|
||||||
d["linked_to_fieldname"], value, value))
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update
|
|
||||||
`tab%s`
|
|
||||||
set
|
|
||||||
%s = CASE %s ELSE `%s` END
|
|
||||||
"""%(d['doctype'], d.linked_to_fieldname, " ".join(when_then), d.linked_to_fieldname))
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user