Merge branch veersion-12-hotfix into plaid-20343-fix

This commit is contained in:
Deepesh Garg
2020-02-17 22:11:14 +05:30
52 changed files with 1643 additions and 3217 deletions

View File

@@ -63,6 +63,7 @@ install:
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
- sudo chmod o+x /usr/local/bin/wkhtmltopdf
- sudo apt-get install libcups2-dev
- cd ~/frappe-bench

View File

@@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"creation": "2017-05-29 21:35:13.136357",
@@ -82,7 +83,7 @@
"default": "0",
"fieldname": "is_default",
"fieldtype": "Check",
"label": "Is the Default Account"
"label": "Is Default Account"
},
{
"default": "0",
@@ -211,7 +212,8 @@
"read_only": 1
}
],
"modified": "2019-10-02 01:34:12.417601",
"links": [],
"modified": "2020-01-29 20:42:26.458316",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Account",

View File

@@ -1,4 +1,5 @@
{
"actions": [],
"allow_copy": 1,
"allow_import": 1,
"allow_rename": 1,
@@ -123,7 +124,8 @@
],
"icon": "fa fa-money",
"idx": 1,
"modified": "2019-09-16 14:44:17.103548",
"links": [],
"modified": "2020-01-28 13:50:23.430434",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@@ -162,7 +164,6 @@
"role": "Purchase User"
}
],
"quick_entry": 1,
"search_fields": "parent_cost_center, is_group",
"show_name_in_global_search": 1,
"sort_field": "modified",

File diff suppressed because it is too large Load Diff

View File

@@ -102,7 +102,9 @@ class PaymentEntry(AccountsController):
self.bank = bank_data.bank
self.bank_account_no = bank_data.bank_account_no
self.set(field, bank_data.account)
if not self.get(field):
self.set(field, bank_data.account)
def validate_allocated_amount(self):
for d in self.get("references"):

View File

@@ -3,6 +3,7 @@
"autoname": "Prompt",
"creation": "2013-05-24 12:15:51",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"disabled",
"section_break_2",
@@ -50,6 +51,7 @@
"income_account",
"expense_account",
"taxes_and_charges",
"tax_category",
"apply_discount_on",
"accounting_dimensions_section",
"cost_center",
@@ -381,11 +383,17 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "tax_category",
"fieldtype": "Link",
"label": "Tax Category",
"options": "Tax Category"
}
],
"icon": "icon-cog",
"idx": 1,
"modified": "2019-05-25 22:56:30.352693",
"modified": "2020-01-24 15:52:03.797701",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -9,6 +9,8 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.healthcare.doctype.lab_test_template.lab_test_template import make_item_price
class TestPricingRule(unittest.TestCase):
def setUp(self):
@@ -145,6 +147,52 @@ class TestPricingRule(unittest.TestCase):
self.assertEquals(details.get("margin_type"), "Percentage")
self.assertEquals(details.get("margin_rate_or_amount"), 10)
def test_mixed_conditions_for_item_group(self):
for item in ["Mixed Cond Item 1", "Mixed Cond Item 2"]:
make_item(item, {"item_group": "Products"})
make_item_price(item, "_Test Price List", 100)
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule for Item Group",
"apply_on": "Item Group",
"item_groups": [
{
"item_group": "Products",
},
{
"item_group": "Seed",
},
],
"selling": 1,
"mixed_conditions": 1,
"currency": "USD",
"rate_or_discount": "Discount Percentage",
"discount_percentage": 10,
"applicable_for": "Customer Group",
"customer_group": "All Customer Groups",
"company": "_Test Company"
}
frappe.get_doc(test_record.copy()).insert()
args = frappe._dict({
"item_code": "Mixed Cond Item 1",
"item_group": "Products",
"company": "_Test Company",
"price_list": "_Test Price List",
"currency": "_Test Currency",
"doctype": "Sales Order",
"conversion_rate": 1,
"price_list_currency": "_Test Currency",
"plc_conversion_rate": 1,
"order_type": "Sales",
"customer": "_Test Customer",
"customer_group": "_Test Customer Group",
"name": None
})
details = get_item_details(args)
self.assertEquals(details.get("discount_percentage"), 10)
def test_pricing_rule_for_variants(self):
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError

View File

@@ -489,7 +489,7 @@ def get_pricing_rule_items(pr_doc):
for d in pr_doc.get(pricing_rule_apply_on):
if apply_on == 'item_group':
get_child_item_groups(d.get(apply_on))
apply_on_data.extend(get_child_item_groups(d.get(apply_on)))
else:
apply_on_data.append(d.get(apply_on))

View File

@@ -1,5 +1,4 @@
{
"actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:05",
@@ -373,7 +372,8 @@
"no_copy": 1,
"options": "Sales Invoice",
"print_hide": 1,
"read_only": 1
"read_only": 1,
"search_index": 1
},
{
"fieldname": "column_break_21",
@@ -1568,8 +1568,7 @@
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
"links": [],
"modified": "2019-12-30 19:15:59.580414",
"modified": "2020-02-10 04:57:11.221180",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -412,6 +412,9 @@ class SalesInvoice(SellingController):
if pos:
self.allow_print_before_pay = pos.allow_print_before_pay
if not for_validate:
self.tax_category = pos.get("tax_category")
if not for_validate and not self.customer:
self.customer = pos.customer

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint
from frappe.utils import cint, cstr
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
from erpnext.accounts.utils import get_fiscal_year
@@ -129,13 +129,13 @@ def get_account_type_based_gl_data(company, start_date, end_date, account_type,
cond = ""
filters = frappe._dict(filters)
if filters.finance_book:
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" %(frappe.db.escape(filters.finance_book))
if filters.include_default_book_entries:
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
if filters.include_default_book_entries:
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
else:
cond = " AND (finance_book in (%s, '') OR finance_book IS NULL)" %(frappe.db.escape(cstr(filters.finance_book)))
cond = """ AND (finance_book in (%s, %s, '') OR finance_book IS NULL)
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)

View File

@@ -387,11 +387,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
if from_date:
additional_conditions.append("gl.posting_date >= %(from_date)s")
if filters.get("finance_book"):
if filters.get("include_default_book_entries"):
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
else:
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
if filters.get("include_default_book_entries"):
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
else:
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""

View File

@@ -13,7 +13,7 @@ import frappe, erpnext
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
from erpnext.accounts.utils import get_fiscal_year
from frappe import _
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate)
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr)
from six import itervalues
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
@@ -348,40 +348,42 @@ def set_gl_entries_by_account(
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
accounts = frappe.db.sql_list("""select name from `tabAccount`
where lft >= %s and rgt <= %s""", (root_lft, root_rgt))
additional_conditions += " and account in ({})"\
.format(", ".join([frappe.db.escape(d) for d in accounts]))
where lft >= %s and rgt <= %s and company = %s""", (root_lft, root_rgt, company))
gl_filters = {
"company": company,
"from_date": from_date,
"to_date": to_date,
"finance_book": filters.get("finance_book")
}
if accounts:
additional_conditions += " and account in ({})"\
.format(", ".join([frappe.db.escape(d) for d in accounts]))
if filters.get("include_default_book_entries"):
gl_filters["company_fb"] = frappe.db.get_value("Company",
company, 'default_finance_book')
gl_filters = {
"company": company,
"from_date": from_date,
"to_date": to_date,
"finance_book": cstr(filters.get("finance_book"))
}
for key, value in filters.items():
if value:
gl_filters.update({
key: value
})
if filters.get("include_default_book_entries"):
gl_filters["company_fb"] = frappe.db.get_value("Company",
company, 'default_finance_book')
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
where company=%(company)s
{additional_conditions}
and posting_date <= %(to_date)s
order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec
for key, value in filters.items():
if value:
gl_filters.update({
key: value
})
if filters and filters.get('presentation_currency'):
convert_to_presentation_currency(gl_entries, get_currency(filters))
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
where company=%(company)s
{additional_conditions}
and posting_date <= %(to_date)s
order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True) #nosec
for entry in gl_entries:
gl_entries_by_account.setdefault(entry.account, []).append(entry)
if filters and filters.get('presentation_currency'):
convert_to_presentation_currency(gl_entries, get_currency(filters))
return gl_entries_by_account
for entry in gl_entries:
gl_entries_by_account.setdefault(entry.account, []).append(entry)
return gl_entries_by_account
def get_additional_conditions(from_date, ignore_closing_entries, filters):
@@ -406,12 +408,11 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
additional_conditions.append("cost_center in %(cost_center)s")
if filters.get("finance_book"):
if filters.get("include_default_book_entries"):
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
else:
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
if filters.get("include_default_book_entries"):
additional_conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
else:
additional_conditions.append("(finance_book in (%(finance_book)s, '') OR finance_book IS NULL)")
if accounting_dimensions:
for dimension in accounting_dimensions:
if filters.get(dimension):

View File

@@ -34,6 +34,20 @@ frappe.query_reports["Item-wise Purchase Register"] = {
"label": __("Mode of Payment"),
"fieldtype": "Link",
"options": "Mode of Payment"
},
{
"label": __("Group By"),
"fieldname": "group_by",
"fieldtype": "Select",
"options": ["Supplier", "Item Group", "Item", "Invoice"]
}
]
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (data && data.bold) {
value = value.bold();
}
return value;
}
}

View File

@@ -5,7 +5,9 @@ from __future__ import unicode_literals
import frappe, erpnext
from frappe import _
from frappe.utils import flt
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import get_tax_accounts
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
get_group_by_conditions)
def execute(filters=None):
return _execute(filters)
@@ -13,7 +15,7 @@ def execute(filters=None):
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {}
filters.update({"from_date": filters.get("date_range")[0], "to_date": filters.get("date_range")[1]})
columns = get_columns(additional_table_columns)
columns = get_columns(additional_table_columns, filters)
company_currency = erpnext.get_company_currency(filters.company)
@@ -23,16 +25,16 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Data",
"width": 80
})
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
data = []
total_row_map = {}
skip_total_row = 0
prev_group_by_value = ''
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Purchase Invoice')
for d in item_list:
if not d.stock_qty:
continue
@@ -44,51 +46,243 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
expense_account = d.expense_account or aii_account_map.get(d.company)
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.supplier,
d.supplier_name]
row = {
'item_code': d.item_code,
'item_name': d.item_name,
'item_group': d.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
'customer': d.supplier,
'customer_name': d.supplier_name
}
if additional_query_columns:
for col in additional_query_columns:
row.append(d.get(col))
row.update({
col: d.get(col)
})
row += [
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_amount / d.stock_qty, d.base_net_amount
]
row.update({
'credit_to': d.credit_to,
'mode_of_payment': d.mode_of_payment,
'project': d.project,
'company': d.company,
'purchase_order': d.purchase_order,
'purchase_receipt': d.purchase_receipt,
'expense_account': expense_account,
'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom,
'rate': d.base_net_amount / d.stock_qty,
'amount': d.base_net_amount
})
total_tax = 0
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
row.update({
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
})
total_tax += flt(item_tax.get("tax_amount"))
row += [total_tax, d.base_net_amount + total_tax, company_currency]
row.update({
'total_tax': total_tax,
'total': d.base_net_amount + total_tax,
'currency': company_currency
})
if filters.get('group_by'):
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
group_by_field, subtotal_display_field, grand_total, tax_columns)
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
data.append(row)
return columns, data
if filters.get('group_by'):
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
data.append(total_row)
data.append({})
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
data.append(total_row_map.get('total_row'))
skip_total_row = 1
return columns, data, None, None, None, skip_total_row
def get_columns(additional_table_columns):
columns = [
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Purchase Invoice:120",
_("Posting Date") + ":Date:80", _("Supplier") + ":Link/Supplier:120",
"Supplier Name::120"
]
def get_columns(additional_table_columns, filters):
columns = []
if filters.get('group_by') != ('Item'):
columns.extend(
[
{
'label': _('Item Code'),
'fieldname': 'item_code',
'fieldtype': 'Link',
'options': 'Item',
'width': 120
},
{
'label': _('Item Name'),
'fieldname': 'item_name',
'fieldtype': 'Data',
'width': 120
}
]
)
if filters.get('group_by') not in ('Item', 'Item Group'):
columns.extend([
{
'label': _('Item Group'),
'fieldname': 'item_group',
'fieldtype': 'Link',
'options': 'Item Group',
'width': 120
}
])
columns.extend([
{
'label': _('Description'),
'fieldname': 'description',
'fieldtype': 'Data',
'width': 150
},
{
'label': _('Invoice'),
'fieldname': 'invoice',
'fieldtype': 'Link',
'options': 'Purchase Invoice',
'width': 120
},
{
'label': _('Posting Date'),
'fieldname': 'posting_date',
'fieldtype': 'Date',
'width': 120
}
])
if filters.get('group_by') != 'Supplier':
columns.extend([
{
'label': _('Supplier'),
'fieldname': 'supplier',
'fieldtype': 'Link',
'options': 'Supplier',
'width': 120
},
{
'label': _('Supplier Name'),
'fieldname': 'supplier_name',
'fieldtype': 'Data',
'width': 120
}
])
if additional_table_columns:
columns += additional_table_columns
columns += [
"Payable Account:Link/Account:120",
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100",
_("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140",
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120"
{
'label': _('Payable Account'),
'fieldname': 'credit_to',
'fieldtype': 'Link',
'options': 'Account',
'width': 80
},
{
'label': _('Mode Of Payment'),
'fieldname': 'mode_of_payment',
'fieldtype': 'Data',
'width': 120
},
{
'label': _('Project'),
'fieldname': 'project',
'fieldtype': 'Link',
'options': 'Project',
'width': 80
},
{
'label': _('Company'),
'fieldname': 'company',
'fieldtype': 'Link',
'options': 'Company',
'width': 80
},
{
'label': _('Purchase Order'),
'fieldname': 'purchase_order',
'fieldtype': 'Link',
'options': 'Purchase Order',
'width': 100
},
{
'label': _("Purchase Receipt"),
'fieldname': 'Purchase Receipt',
'fieldtype': 'Link',
'options': 'Purchase Receipt',
'width': 100
},
{
'label': _('Expense Account'),
'fieldname': 'expense_account',
'fieldtype': 'Link',
'options': 'Account',
'width': 100
},
{
'label': _('Stock Qty'),
'fieldname': 'stock_qty',
'fieldtype': 'Float',
'width': 100
},
{
'label': _('Stock UOM'),
'fieldname': 'stock_uom',
'fieldtype': 'Link',
'options': 'UOM',
'width': 100
},
{
'label': _('Rate'),
'fieldname': 'rate',
'fieldtype': 'Float',
'options': 'currency',
'width': 100
},
{
'label': _('Amount'),
'fieldname': 'amount',
'fieldtype': 'Currency',
'options': 'currency',
'width': 100
},
{
'fieldname': 'currency',
'label': _('Currency'),
'fieldtype': 'Currency',
'width': 80,
'hidden': 1
}
]
if filters.get('group_by'):
columns.append({
'label': _('% Of Grand Total'),
'fieldname': 'percent_gt',
'fieldtype': 'Float',
'width': 80
})
return columns
def get_conditions(filters):
@@ -103,6 +297,11 @@ def get_conditions(filters):
if filters.get(opts[0]):
conditions += opts[1]
if not filters.get("group_by"):
conditions += "ORDER BY `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc"
else:
conditions += get_group_by_conditions(filters, 'Purchase Invoice')
return conditions
def get_items(filters, additional_query_columns):
@@ -129,7 +328,6 @@ def get_items(filters, additional_query_columns):
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
`tabPurchase Invoice`.docstatus = 1 %s %s
order by `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
def get_aii_accounts():

View File

@@ -4,48 +4,62 @@
frappe.query_reports["Item-wise Sales Register"] = {
"filters": [
{
"fieldname":"date_range",
"fieldname": "date_range",
"label": __("Date Range"),
"fieldtype": "DateRange",
"default": [frappe.datetime.add_months(frappe.datetime.get_today(),-1), frappe.datetime.get_today()],
"reqd": 1
},
{
"fieldname":"customer",
"fieldname": "customer",
"label": __("Customer"),
"fieldtype": "Link",
"options": "Customer"
},
{
"fieldname":"company",
"fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"mode_of_payment",
"fieldname": "mode_of_payment",
"label": __("Mode of Payment"),
"fieldtype": "Link",
"options": "Mode of Payment"
},
{
"fieldname":"warehouse",
"fieldname": "warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"options": "Warehouse"
},
{
"fieldname":"brand",
"fieldname": "brand",
"label": __("Brand"),
"fieldtype": "Link",
"options": "Brand"
},
{
"fieldname":"item_group",
"fieldname": "item_group",
"label": __("Item Group"),
"fieldtype": "Link",
"options": "Item Group"
},
{
"label": __("Group By"),
"fieldname": "group_by",
"fieldtype": "Select",
"options": ["Customer Group", "Customer", "Item Group", "Item", "Territory", "Invoice"]
}
]
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (data && data.bold) {
value = value.bold();
}
return value;
}
}

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _
from frappe.utils import flt
from frappe.utils import flt, cstr
from frappe.model.meta import get_field_precision
from frappe.utils.xlsxutils import handle_html
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
@@ -15,23 +15,25 @@ def execute(filters=None):
def _execute(filters=None, additional_table_columns=None, additional_query_columns=None):
if not filters: filters = {}
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
columns = get_columns(additional_table_columns)
columns = get_columns(additional_table_columns, filters)
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
item_list = get_items(filters, additional_query_columns)
if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Data",
"width": 80
})
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)
data = []
total_row_map = {}
skip_total_row = 0
prev_group_by_value = ''
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Sales Invoice')
for d in item_list:
delivery_note = None
if d.delivery_note:
@@ -42,57 +44,285 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if not delivery_note and d.update_stock:
delivery_note = d.parent
row = [d.item_code, d.item_name, d.item_group, d.description, d.parent, d.posting_date, d.customer, d.customer_name]
row = {
'item_code': d.item_code,
'item_name': d.item_name,
'item_group': d.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
'customer': d.customer,
'customer_name': d.customer_name,
'customer_group': d.customer_group,
}
if additional_query_columns:
for col in additional_query_columns:
row.append(d.get(col))
row.update({
col: d.get(col)
})
row += [
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
d.territory, d.project, d.company, d.sales_order,
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
]
row.update({
'debit_to': d.debit_to,
'mode_of_payment': ", ".join(mode_of_payments.get(d.parent, [])),
'territory': d.territory,
'project': d.project,
'company': d.company,
'sales_order': d.sales_order,
'delivery_note': d.delivery_note,
'income_account': d.income_account,
'cost_center': d.cost_center,
'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom
})
if d.stock_uom != d.uom and d.stock_qty:
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
row.update({
'rate': (d.base_net_rate * d.qty)/d.stock_qty,
'amount': d.base_net_amount
})
else:
row += [d.base_net_rate, d.base_net_amount]
row.update({
'rate': d.base_net_rate,
'amount': d.base_net_amount
})
total_tax = 0
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row += [item_tax.get("tax_rate", 0), item_tax.get("tax_amount", 0)]
row.update({
frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
})
total_tax += flt(item_tax.get("tax_amount"))
row += [total_tax, d.base_net_amount + total_tax, company_currency]
row.update({
'total_tax': total_tax,
'total': d.base_net_amount + total_tax,
'currency': company_currency
})
if filters.get('group_by'):
row.update({'percent_gt': flt(row['total']/grand_total) * 100})
group_by_field, subtotal_display_field = get_group_by_and_display_fields(filters)
data, prev_group_by_value = add_total_row(data, filters, prev_group_by_value, d, total_row_map,
group_by_field, subtotal_display_field, grand_total, tax_columns)
add_sub_total_row(row, total_row_map, d.get(group_by_field, ''), tax_columns)
data.append(row)
return columns, data
if filters.get('group_by'):
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
data.append(total_row)
data.append({})
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
data.append(total_row_map.get('total_row'))
skip_total_row = 1
return columns, data, None, None, None, skip_total_row
def get_columns(additional_table_columns):
columns = [
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120",
_("Item Group") + ":Link/Item Group:100", "Description::150", _("Invoice") + ":Link/Sales Invoice:120",
_("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
_("Customer Name") + "::120"]
def get_columns(additional_table_columns, filters):
columns = []
if filters.get('group_by') != ('Item'):
columns.extend(
[
{
'label': _('Item Code'),
'fieldname': 'item_code',
'fieldtype': 'Link',
'options': 'Item',
'width': 120
},
{
'label': _('Item Name'),
'fieldname': 'item_name',
'fieldtype': 'Data',
'width': 120
}
]
)
if filters.get('group_by') not in ('Item', 'Item Group'):
columns.extend([
{
'label': _('Item Group'),
'fieldname': 'item_group',
'fieldtype': 'Link',
'options': 'Item Group',
'width': 120
}
])
columns.extend([
{
'label': _('Description'),
'fieldname': 'description',
'fieldtype': 'Data',
'width': 150
},
{
'label': _('Invoice'),
'fieldname': 'invoice',
'fieldtype': 'Link',
'options': 'Sales Invoice',
'width': 120
},
{
'label': _('Posting Date'),
'fieldname': 'posting_date',
'fieldtype': 'Date',
'width': 120
}
])
if filters.get('group_by') != 'Customer':
columns.extend([
{
'label': _('Customer Group'),
'fieldname': 'customer_group',
'fieldtype': 'Link',
'options': 'Customer Group',
'width': 120
}
])
if filters.get('group_by') not in ('Customer', 'Customer Group'):
columns.extend([
{
'label': _('Customer'),
'fieldname': 'customer',
'fieldtype': 'Link',
'options': 'Customer',
'width': 120
},
{
'label': _('Customer Name'),
'fieldname': 'customer_name',
'fieldtype': 'Data',
'width': 120
}
])
if additional_table_columns:
columns += additional_table_columns
columns += [
_("Customer Group") + ":Link/Customer Group:120",
_("Receivable Account") + ":Link/Account:120",
_("Mode of Payment") + "::120", _("Territory") + ":Link/Territory:80",
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
_("Income Account") + ":Link/Account:140", _("Cost Center") + ":Link/Cost Center:140",
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Rate") + ":Currency/currency:120",
_("Amount") + ":Currency/currency:120"
{
'label': _('Receivable Account'),
'fieldname': 'debit_to',
'fieldtype': 'Link',
'options': 'Account',
'width': 80
},
{
'label': _('Mode Of Payment'),
'fieldname': 'mode_of_payment',
'fieldtype': 'Data',
'width': 120
}
]
if filters.get('group_by') != 'Terriotory':
columns.extend([
{
'label': _("Territory"),
'fieldname': 'territory',
'fieldtype': 'Link',
'options': 'Territory',
'width': 80
}
])
columns += [
{
'label': _('Project'),
'fieldname': 'project',
'fieldtype': 'Link',
'options': 'Project',
'width': 80
},
{
'label': _('Company'),
'fieldname': 'company',
'fieldtype': 'Link',
'options': 'Company',
'width': 80
},
{
'label': _('Sales Order'),
'fieldname': 'sales_order',
'fieldtype': 'Link',
'options': 'Sales Order',
'width': 100
},
{
'label': _("Delivery Note"),
'fieldname': 'delivery_note',
'fieldtype': 'Link',
'options': 'Delivery Note',
'width': 100
},
{
'label': _('Income Account'),
'fieldname': 'income_account',
'fieldtype': 'Link',
'options': 'Account',
'width': 100
},
{
'label': _("Cost Center"),
'fieldname': 'cost_center',
'fieldtype': 'Link',
'options': 'Cost Center',
'width': 100
},
{
'label': _('Stock Qty'),
'fieldname': 'stock_qty',
'fieldtype': 'Float',
'width': 100
},
{
'label': _('Stock UOM'),
'fieldname': 'stock_uom',
'fieldtype': 'Link',
'options': 'UOM',
'width': 100
},
{
'label': _('Rate'),
'fieldname': 'rate',
'fieldtype': 'Float',
'options': 'currency',
'width': 100
},
{
'label': _('Amount'),
'fieldname': 'amount',
'fieldtype': 'Currency',
'options': 'currency',
'width': 100
},
{
'fieldname': 'currency',
'label': _('Currency'),
'fieldtype': 'Currency',
'width': 80,
'hidden': 1
}
]
if filters.get('group_by'):
columns.append({
'label': _('% Of Grand Total'),
'fieldname': 'percent_gt',
'fieldtype': 'Float',
'width': 80
})
return columns
def get_conditions(filters):
@@ -112,24 +342,32 @@ def get_conditions(filters):
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
if filters.get("warehouse"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s)"""
conditions += """and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s"""
if filters.get("brand"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s)"""
conditions += """and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s"""
if filters.get("item_group"):
conditions += """ and exists(select name from `tabSales Invoice Item`
where parent=`tabSales Invoice`.name
and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s)"""
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
if not filters.get("group_by"):
conditions += "ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
else:
conditions += get_group_by_conditions(filters, 'Sales Invoice')
return conditions
def get_group_by_conditions(filters, doctype):
if filters.get("group_by") == 'Invoice':
return "ORDER BY `tab{0} Item`.parent desc".format(doctype)
elif filters.get("group_by") == 'Item':
return "ORDER BY `tab{0} Item`.`item_code`".format(doctype)
elif filters.get("group_by") == 'Item Group':
return "ORDER BY `tab{0} Item`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
elif filters.get("group_by") in ('Customer', 'Customer Group', 'Territory', 'Supplier'):
return "ORDER BY `tab{0}`.{1}".format(doctype, frappe.scrub(filters.get('group_by')))
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Sales Invoice")
@@ -156,9 +394,8 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
and `tabSales Invoice`.docstatus = 1 %s %s
order by `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_code desc
""".format(additional_query_columns or '') % (conditions, match_conditions), filters, as_dict=1)
and `tabSales Invoice`.docstatus = 1 {1} {2}
""".format(additional_query_columns or '', conditions, match_conditions), filters, as_dict=1) #nosec
def get_delivery_notes_against_sales_order(item_list):
so_dn_map = frappe._dict()
@@ -177,6 +414,15 @@ def get_delivery_notes_against_sales_order(item_list):
return so_dn_map
def get_grand_total(filters, doctype):
return frappe.db.sql(""" SELECT
SUM(`tab{0}`.base_grand_total)
FROM `tab{0}`
WHERE `tab{0}`.docstatus = 1
and posting_date between %s and %s
""".format(doctype), (filters.get('from_date'), filters.get('to_date')))[0][0] #nosec
def get_deducted_taxes():
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
@@ -264,9 +510,117 @@ def get_tax_accounts(item_list, columns, company_currency,
tax_columns.sort()
for desc in tax_columns:
columns.append(desc + " Rate:Data:80")
columns.append(desc + " Amount:Currency/currency:100")
columns.append({
'label': _(desc + ' Rate'),
'fieldname': frappe.scrub(desc + ' Rate'),
'fieldtype': 'Float',
'width': 100
})
columns += ["Total Tax:Currency/currency:80", "Total:Currency/currency:100"]
columns.append({
'label': _(desc + ' Amount'),
'fieldname': frappe.scrub(desc + ' Amount'),
'fieldtype': 'Currency',
'options': 'currency',
'width': 100
})
columns += [
{
'label': _('Total Tax'),
'fieldname': 'total_tax',
'fieldtype': 'Currency',
'options': 'currency',
'width': 100
},
{
'label': _('Total'),
'fieldname': 'total',
'fieldtype': 'Currency',
'options': 'currency',
'width': 100
}
]
return itemised_tax, tax_columns
def add_total_row(data, filters, prev_group_by_value, item, total_row_map,
group_by_field, subtotal_display_field, grand_total, tax_columns):
if prev_group_by_value != item.get(group_by_field, ''):
if prev_group_by_value:
total_row = total_row_map.get(prev_group_by_value)
data.append(total_row)
data.append({})
add_sub_total_row(total_row, total_row_map, 'total_row', tax_columns)
prev_group_by_value = item.get(group_by_field, '')
total_row_map.setdefault(item.get(group_by_field, ''), {
subtotal_display_field: get_display_value(filters, group_by_field, item),
'stock_qty': 0.0,
'amount': 0.0,
'bold': 1,
'total_tax': 0.0,
'total': 0.0,
'percent_gt': 0.0
})
total_row_map.setdefault('total_row', {
subtotal_display_field: "Total",
'stock_qty': 0.0,
'amount': 0.0,
'bold': 1,
'total_tax': 0.0,
'total': 0.0,
'percent_gt': 0.0
})
return data, prev_group_by_value
def get_display_value(filters, group_by_field, item):
if filters.get('group_by') == 'Item':
if item.get('item_code') != item.get('item_name'):
value = cstr(item.get('item_code')) + "<br><br>" + \
"<span style='font-weight: normal'>" + cstr(item.get('item_name')) + "</span>"
else:
value = item.get('item_code', '')
elif filters.get('group_by') in ('Customer', 'Supplier'):
party = frappe.scrub(filters.get('group_by'))
if item.get(party) != item.get(party+'_name'):
value = item.get(party) + "<br><br>" + \
"<span style='font-weight: normal'>" + item.get(party+'_name') + "</span>"
else:
value = item.get(party)
else:
value = item.get(group_by_field)
return value
def get_group_by_and_display_fields(filters):
if filters.get('group_by') == 'Item':
group_by_field = 'item_code'
subtotal_display_field = 'invoice'
elif filters.get('group_by') == 'Invoice':
group_by_field = 'parent'
subtotal_display_field = 'item_code'
else:
group_by_field = frappe.scrub(filters.get('group_by'))
subtotal_display_field = 'item_code'
return group_by_field, subtotal_display_field
def add_sub_total_row(item, total_row_map, group_by_value, tax_columns):
total_row = total_row_map.get(group_by_value)
total_row['stock_qty'] += item['stock_qty']
total_row['amount'] += item['amount']
total_row['total_tax'] += item['total_tax']
total_row['total'] += item['total']
total_row['percent_gt'] += item['percent_gt']
for tax in tax_columns:
total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0)
total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')])

View File

@@ -139,7 +139,7 @@ def get_columns(invoice_list, additional_table_columns):
columns +=[
{
'label': _("Custmer Group"),
'label': _("Customer Group"),
'fieldname': 'customer_group',
'fieldtype': 'Link',
'options': 'Customer Group',
@@ -175,7 +175,7 @@ def get_columns(invoice_list, additional_table_columns):
'label': _("Project"),
'fieldname': 'project',
'fieldtype': 'Link',
'options': 'project',
'options': 'Project',
'width': 80
},
{

View File

@@ -1,580 +1,146 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:location_name",
"beta": 0,
"creation": "2018-05-07 12:49:22.595974",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"location_name",
"parent_location",
"cb_details",
"is_container",
"is_group",
"sb_location_details",
"latitude",
"longitude",
"cb_latlong",
"area",
"area_uom",
"sb_geolocation",
"location",
"tree_details",
"lft",
"rgt",
"old_parent"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "location_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Location Name",
"length": 0,
"no_copy": 1,
"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,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "parent_location",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Parent Location",
"length": 0,
"no_copy": 0,
"options": "Location",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cb_details",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "Check if it is a hydroponic unit",
"fieldname": "is_container",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Container",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Is Container"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Is Group",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Is Group"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sb_location_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Location Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Location Details"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "parent_location.latitude",
"fieldname": "latitude",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Latitude",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Latitude"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "parent_location.longitude",
"fieldname": "longitude",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Longitude",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Longitude"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cb_latlong",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "area",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Area",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.area",
"fieldname": "area_uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Area UOM",
"length": 0,
"no_copy": 0,
"options": "UOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "UOM"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sb_geolocation",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "location",
"fieldtype": "Geolocation",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Location",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Location"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tree_details",
"fieldtype": "Section Break",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Tree Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Tree Details"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "lft",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "rgt",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "old_parent",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Old Parent",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-07-11 13:36:30.999405",
"links": [],
"modified": "2020-01-28 13:52:22.513425",
"modified_by": "Administrator",
"module": "Assets",
"name": "Location",
@@ -582,127 +148,78 @@
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Agriculture Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Agriculture User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
"track_changes": 1
}

View File

@@ -141,13 +141,13 @@ def get_conditions(filters):
conditions = ""
if filters.get("company"):
conditions += " AND company='%s'"% filters.get('company')
conditions += " AND company=%s"% frappe.db.escape(filters.get('company'))
if filters.get("cost_center") or filters.get("project"):
conditions += """
AND (cost_center='%s'
OR project='%s')
"""% (filters.get('cost_center'), filters.get('project'))
AND (cost_center=%s
OR project=%s)
"""% (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
if filters.get("from_date"):
conditions += " AND transaction_date>=%s"% filters.get('from_date')

View File

@@ -1135,6 +1135,7 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
child_item.reqd_by_date = p_doctype.delivery_date
child_item.uom = item.stock_uom
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.warehouse = p_doctype.set_warehouse or p_doctype.items[0].warehouse
return child_item

View File

@@ -123,9 +123,11 @@ def get_students(student_group, academic_year, academic_term=None, student_categ
students = frappe.db.sql("""
select pe.student, pe.student_name, pe.program, pe.student_batch_name
from `tabStudent Group Student` sgs, `tabProgram Enrollment` pe
from `tabStudent Group Student` sgs, `tabProgram Enrollment` pe, `tabStudent Group` sg
where
pe.student = sgs.student and pe.academic_year = %s
and sg.program = pe.program
and sg.name = sgs.parent
and sgs.parent = %s and sgs.active = 1
{conditions}
""".format(conditions=conditions), (academic_year, student_group), as_dict=1)

View File

@@ -2,7 +2,9 @@
// For license information, please see license.txt
frappe.ui.form.on('Employee Checkin', {
// refresh: function(frm) {
// }
setup: (frm) => {
if(!frm.doc.time) {
frm.set_value("time", frappe.datetime.now_datetime());
}
}
});

View File

@@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"autoname": "EMP-CKIN-.MM.-.YYYY.-.######",
"creation": "2019-06-10 11:56:34.536413",
@@ -23,7 +24,6 @@
{
"fieldname": "employee",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Employee",
"options": "Employee",
"reqd": 1
@@ -32,14 +32,17 @@
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Employee Name",
"read_only": 1
},
{
"fieldname": "log_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Log Type",
"options": "\nIN\nOUT"
"options": "\nIN\nOUT",
"reqd": 1
},
{
"fieldname": "shift",
@@ -58,6 +61,7 @@
"fieldtype": "Datetime",
"in_list_view": 1,
"label": "Time",
"permlevel": 1,
"reqd": 1
},
{
@@ -103,7 +107,8 @@
"label": "Shift Actual End"
}
],
"modified": "2019-07-23 23:47:33.975263",
"links": [],
"modified": "2020-01-23 04:57:42.551355",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Checkin",
@@ -147,9 +152,58 @@
"role": "HR User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"read": 1,
"role": "Employee",
"write": 1
},
{
"delete": 1,
"email": 1,
"export": 1,
"permlevel": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"delete": 1,
"email": 1,
"export": 1,
"permlevel": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
"share": 1,
"write": 1
},
{
"delete": 1,
"email": 1,
"export": 1,
"permlevel": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
"share": 1,
"write": 1
},
{
"permlevel": 1,
"read": 1,
"role": "Employee"
}
],
"sort_field": "modified",
"sort_order": "ASC",
"title_field": "employee_name",
"track_changes": 1
}

View File

@@ -104,11 +104,16 @@ frappe.ui.form.on("Leave Application", {
},
half_day: function(frm) {
if (frm.doc.from_date == frm.doc.to_date) {
frm.set_value("half_day_date", frm.doc.from_date);
if (frm.doc.half_day) {
if (frm.doc.from_date == frm.doc.to_date) {
frm.set_value("half_day_date", frm.doc.from_date);
}
else {
frm.trigger("half_day_datepicker");
}
}
else {
frm.trigger("half_day_datepicker");
frm.set_value("half_day_date", "");
}
frm.trigger("calculate_total_days");
},

View File

@@ -193,7 +193,7 @@ class MaintenanceSchedule(TransactionBase):
if sr_details.amc_expiry_date and getdate(sr_details.amc_expiry_date) >= getdate(amc_start_date):
throw(_("Serial No {0} is under maintenance contract upto {1}")
.format(serial_no, sr_details.amc_start_date))
.format(serial_no, sr_details.amc_expiry_date))
if not sr_details.warehouse and sr_details.delivery_date and \
getdate(sr_details.delivery_date) >= getdate(amc_start_date):

View File

@@ -625,7 +625,6 @@ def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None):
for data in po_items:
planned_qty = data.get('required_qty') or data.get('planned_qty')
ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or ignore_existing_ordered_qty
warehouse = data.get("warehouse") or warehouse
item_details = {}
if data.get("bom") or data.get("bom_no"):

View File

@@ -649,3 +649,4 @@ erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger
erpnext.patches.v12_0.update_price_or_product_discount
erpnext.patches.v12_0.add_export_type_field_in_party_master
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
erpnext.patches.v12_0.create_irs_1099_field_united_states

View File

@@ -0,0 +1,10 @@
from __future__ import unicode_literals
import frappe
from erpnext.regional.united_states.setup import make_custom_fields
def execute():
company = frappe.get_all('Company', filters = {'country': 'United States'})
if not company:
return
make_custom_fields()

View File

@@ -1,4 +1,5 @@
import frappe
import numpy as np
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
def get_field_filter_data():
@@ -172,6 +173,7 @@ def get_attributes_and_values(item_code):
item_attribute_values = frappe.db.get_all('Item Attribute Value',
['parent', 'attribute_value', 'idx'], order_by='parent asc, idx asc')
item_attribute_values += get_numeric_values()
ordered_attribute_value_map = frappe._dict()
for iv in item_attribute_values:
ordered_attribute_value_map.setdefault(iv.parent, []).append(iv.attribute_value)
@@ -184,6 +186,23 @@ def get_attributes_and_values(item_code):
return attributes
def get_numeric_values():
attribute_values_list = []
numeric_attributes = frappe.get_list("Item Attribute", fields=['name', 'from_range', 'to_range', 'increment'], filters={"numeric_values": 1})
for attribute in numeric_attributes:
from_range = attribute["from_range"]
to_range = attribute['to_range'] + attribute['increment']
increment = attribute['increment']
values = list(np.arange(from_range, to_range, increment))
for idx, val in enumerate(values):
attribute_values_list.append(frappe._dict({
"parent": attribute.get("name"),
"attribute_value": str(int(val)) if val.is_integer() else str(val),
"idx": idx
}))
return attribute_values_list
@frappe.whitelist(allow_guest=True)
def get_next_attribute_and_values(item_code, selected_attributes):

View File

@@ -1,4 +1,5 @@
{
"actions": [],
"creation": "2016-03-25 02:52:19.283003",
"doctype": "DocType",
"editable_grid": 1,
@@ -46,6 +47,7 @@
"fetch_from": "user.full_name",
"fieldname": "full_name",
"fieldtype": "Read Only",
"in_list_view": 1,
"label": "Full Name"
},
{
@@ -55,7 +57,7 @@
"label": "Welcome email sent"
},
{
"columns": 1,
"columns": 2,
"default": "0",
"fieldname": "view_attachments",
"fieldtype": "Check",
@@ -74,7 +76,8 @@
}
],
"istable": 1,
"modified": "2019-07-15 19:37:26.942294",
"links": [],
"modified": "2020-02-09 23:26:50.321417",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project User",

View File

@@ -90,7 +90,8 @@ erpnext.SerialNoBatchSelector = Class.extend({
args: {
qty: qty,
item_code: me.item_code,
warehouse: me.warehouse_details.name
warehouse: me.warehouse_details.name,
batch_no: me.item.batch_no || null
}
});
@@ -392,7 +393,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
delivery_document_no: ""
}
if (this.has_batch) {
if (this.item.batch_no) {
serial_no_filters["batch_no"] = this.item.batch_no;
}

View File

@@ -73,7 +73,7 @@
"reqd": 1
}
],
"modified": "2019-05-26 23:12:47.302189",
"modified": "2020-02-01 10:57:27.119312",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality Review",
@@ -102,6 +102,18 @@
"role": "All",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Quality Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",

View File

@@ -1,24 +1,28 @@
{
"add_total_row": 0,
"creation": "2018-10-16 12:28:43.651915",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2018-10-16 15:23:25.667237",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Review",
"owner": "Administrator",
"prepared_report": 0,
"query": "SELECT\n `tabQuality Action`.name as \"Name:Data:200\",\n `tabQuality Action`.action as \"Action:Select/[corrective,Preventive]:200\",\n `tabQuality Action`.review as \"Review:Link/Quality Review:200\",\n `tabQuality Action`.date as \"Date:Date:120\",\n `tabQuality Action`.status as \"Status:Select/Planned:150\"\nFROM\n `tabQuality Action`\nWHERE\n `tabQuality Action`.type='Quality Review'\n \n ",
"ref_doctype": "Quality Action",
"report_name": "Review",
"report_type": "Query Report",
"add_total_row": 0,
"creation": "2018-10-16 12:28:43.651915",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2020-02-01 11:04:47.299453",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Review",
"owner": "Administrator",
"prepared_report": 0,
"query": "SELECT\n `tabQuality Action`.name as \"Name:Data:200\",\n `tabQuality Action`.corrective_preventive as \"Action:Select/[Corrective,Preventive]:200\",\n `tabQuality Action`.document_type as \"Document Type:Select/[Quality Review, Quality Feedback]:200\",\n `tabQuality Action`.date as \"Date:Date:120\",\n `tabQuality Action`.status as \"Status:Select/Planned:150\"\nFROM\n `tabQuality Action`\nWHERE\n `tabQuality Action`.document_type='Quality Review'\n \n ",
"ref_doctype": "Quality Action",
"report_name": "Review",
"report_type": "Query Report",
"roles": [
{
"role": "System Manager"
},
{
"role": "Quality Manager"
}
]
}

View File

@@ -79,9 +79,10 @@ def add_custom_roles_for_reports():
def add_permissions():
for doctype in ('GST HSN Code', 'GST Settings'):
add_permission(doctype, 'All', 0)
add_permission(doctype, 'Accounts Manager', 0)
update_permission_property(doctype, 'Accounts Manager', 0, 'write', 1)
update_permission_property(doctype, 'Accounts Manager', 0, 'create', 1)
for role in ('Accounts Manager', 'System Manager', 'Item Manager', 'Stock Manager'):
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, 'write', 1)
update_permission_property(doctype, role, 0, 'create', 1)
def add_print_formats():
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
@@ -718,4 +719,4 @@ def get_tds_details(accounts, fiscal_year):
doctype="Tax Withholding Category", accounts=accounts,
rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
"single_threshold": 2500, "cumulative_threshold": 0}])
]
]

View File

@@ -160,7 +160,7 @@ def get_gl_entries(filters, as_dict):
where gl.company = %(company)s
and DATE(gl.posting_date) >= %(from_date)s
and DATE(gl.posting_date) <= %(to_date)s
order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1)
order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict)
return gl_entries

View File

@@ -55,6 +55,14 @@ frappe.ui.form.on("Customer", {
}
}
})
frm.set_query('default_bank_account', function() {
return {
filters: {
'is_company_account': 1
}
}
});
},
customer_primary_address: function(frm){
if(frm.doc.customer_primary_address){

View File

@@ -1,4 +1,5 @@
{
"actions": [],
"allow_events_in_timeline": 1,
"allow_import": 1,
"allow_rename": 1,
@@ -122,7 +123,7 @@
{
"fieldname": "default_bank_account",
"fieldtype": "Link",
"label": "Default Bank Account",
"label": "Default Company Bank Account",
"options": "Bank Account"
},
{
@@ -470,7 +471,8 @@
"icon": "fa fa-user",
"idx": 363,
"image_field": "image",
"modified": "2020-01-24 15:06:03.483799",
"links": [],
"modified": "2020-01-29 20:36:37.879581",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",

View File

@@ -54,6 +54,7 @@ class Customer(TransactionBase):
self.validate_credit_limit_on_change()
self.set_loyalty_program()
self.check_customer_group_change()
self.validate_default_bank_account()
# set loyalty program tier
if frappe.db.exists('Customer', self.name):
@@ -72,6 +73,11 @@ class Customer(TransactionBase):
if self.customer_group != frappe.db.get_value('Customer', self.name, 'customer_group'):
frappe.flags.customer_group_changed = True
def validate_default_bank_account(self):
if self.default_bank_account:
is_company_account = frappe.db.get_value('Bank Account', self.default_bank_account, 'is_company_account')
frappe.throw(_("{0} is not a company bank account").format(frappe.bold(self.default_bank_account)))
def on_update(self):
self.validate_name_with_customer_group()
self.create_primary_contact()

View File

@@ -1,11 +1,12 @@
{
"_comments": "[]",
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:customer_group_name",
"creation": "2013-01-10 16:34:23",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"customer_group_name",
"parent_customer_group",
@@ -136,7 +137,8 @@
],
"icon": "fa fa-sitemap",
"idx": 1,
"modified": "2019-09-06 12:40:14.954697",
"links": [],
"modified": "2020-01-28 13:49:23.961708",
"modified_by": "Administrator",
"module": "Setup",
"name": "Customer Group",
@@ -187,8 +189,8 @@
"role": "Sales Manager"
}
],
"quick_entry": 1,
"search_fields": "parent_customer_group",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

File diff suppressed because it is too large Load Diff

View File

@@ -174,15 +174,11 @@ def get_child_groups(item_group_name):
and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
def get_child_item_groups(item_group_name):
child_item_groups = frappe.cache().hget("child_item_groups", item_group_name)
item_group = frappe.get_cached_value("Item Group",
item_group_name, ["lft", "rgt"], as_dict=1)
if not child_item_groups:
item_group = frappe.get_cached_doc("Item Group", item_group_name)
child_item_groups = [d.name for d in frappe.get_all('Item Group',
filters= {'lft': ('>=', item_group.lft),'rgt': ('>=', item_group.rgt)})]
frappe.cache().hset("child_item_groups", item_group_name, child_item_groups)
child_item_groups = [d.name for d in frappe.get_all('Item Group',
filters= {'lft': ('>=', item_group.lft),'rgt': ('<=', item_group.rgt)})]
return child_item_groups or {}

View File

@@ -1,579 +1,183 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:sales_person_name",
"beta": 0,
"creation": "2013-01-10 16:34:24",
"custom": 0,
"description": "All Sales Transactions can be tagged against multiple **Sales Persons** so that you can set and monitor targets.",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"engine": "InnoDB",
"field_order": [
"name_and_employee_id",
"sales_person_name",
"parent_sales_person",
"commission_rate",
"is_group",
"enabled",
"cb0",
"employee",
"department",
"lft",
"rgt",
"old_parent",
"target_details_section_break",
"targets"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "name_and_employee_id",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Name and Employee ID",
"length": 0,
"no_copy": 0,
"options": "icon-user",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "icon-user"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_person_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Sales Person Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "sales_person_name",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Select company name first.",
"fetch_if_empty": 0,
"fieldname": "parent_sales_person",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Parent Sales Person",
"length": 0,
"no_copy": 0,
"oldfieldname": "parent_sales_person",
"oldfieldtype": "Link",
"options": "Sales Person",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Sales Person"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "commission_rate",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Commission Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"print_hide": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Is Group",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_group",
"oldfieldtype": "Select",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fetch_if_empty": 0,
"fieldname": "enabled",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Enabled",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"label": "Enabled"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "cb0",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee",
"length": 0,
"no_copy": 0,
"options": "Employee",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Employee"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
"fetch_if_empty": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Department",
"length": 0,
"no_copy": 0,
"options": "Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "lft",
"length": 0,
"no_copy": 1,
"oldfieldname": "lft",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "rgt",
"length": 0,
"no_copy": 1,
"oldfieldname": "rgt",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "old_parent",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "old_parent",
"length": 0,
"no_copy": 1,
"oldfieldname": "old_parent",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"print_hide": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Set targets Item Group-wise for this Sales Person.",
"fetch_if_empty": 0,
"fieldname": "target_details_section_break",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Sales Person Targets",
"length": 0,
"no_copy": 0,
"oldfieldtype": "Section Break",
"options": "icon-bullseye",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "icon-bullseye"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "targets",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Targets",
"length": 0,
"no_copy": 0,
"oldfieldname": "target_details",
"oldfieldtype": "Table",
"options": "Target Detail",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"options": "Target Detail"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-user",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-22 16:26:01.706129",
"links": [],
"modified": "2020-01-28 13:50:31.891050",
"modified_by": "Administrator",
"module": "Setup",
"name": "Sales Person",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales Manager"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales User"
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "parent_sales_person",
"show_name_in_global_search": 1,
"sort_order": "ASC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
"sort_field": "modified",
"sort_order": "ASC"
}

View File

@@ -1,487 +1,173 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:territory_name",
"beta": 0,
"creation": "2013-01-10 16:34:24",
"custom": 0,
"description": "Classification of Customers by region",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:territory_name",
"creation": "2013-01-10 16:34:24",
"description": "Classification of Customers by region",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"territory_name",
"parent_territory",
"is_group",
"cb0",
"territory_manager",
"lft",
"rgt",
"old_parent",
"target_details_section_break",
"targets"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "territory_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Territory Name",
"length": 0,
"no_copy": 1,
"oldfieldname": "territory_name",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"fieldname": "territory_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Territory Name",
"no_copy": 1,
"oldfieldname": "territory_name",
"oldfieldtype": "Data",
"reqd": 1,
"unique": 1
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "parent_territory",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Parent Territory",
"length": 0,
"no_copy": 0,
"oldfieldname": "parent_territory",
"oldfieldtype": "Link",
"options": "Territory",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"bold": 1,
"fieldname": "parent_territory",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"in_list_view": 1,
"label": "Parent Territory",
"oldfieldname": "parent_territory",
"oldfieldtype": "Link",
"options": "Territory"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Is Group",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_group",
"oldfieldtype": "Select",
"options": "",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"bold": 1,
"default": "0",
"fieldname": "is_group",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Is Group",
"oldfieldname": "is_group",
"oldfieldtype": "Select"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "cb0",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "cb0",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "For reference",
"fetch_if_empty": 0,
"fieldname": "territory_manager",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Territory Manager",
"length": 0,
"no_copy": 0,
"oldfieldname": "territory_manager",
"oldfieldtype": "Link",
"options": "Sales Person",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"description": "For reference",
"fieldname": "territory_manager",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Territory Manager",
"oldfieldname": "territory_manager",
"oldfieldtype": "Link",
"options": "Sales Person",
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "lft",
"length": 0,
"no_copy": 1,
"oldfieldname": "lft",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"label": "lft",
"no_copy": 1,
"oldfieldname": "lft",
"oldfieldtype": "Int",
"print_hide": 1,
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "rgt",
"length": 0,
"no_copy": 1,
"oldfieldname": "rgt",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"label": "rgt",
"no_copy": 1,
"oldfieldname": "rgt",
"oldfieldtype": "Int",
"print_hide": 1,
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fetch_if_empty": 0,
"fieldname": "old_parent",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "old_parent",
"length": 0,
"no_copy": 1,
"oldfieldname": "old_parent",
"oldfieldtype": "Data",
"options": "Territory",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "old_parent",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
"label": "old_parent",
"no_copy": 1,
"oldfieldname": "old_parent",
"oldfieldtype": "Data",
"options": "Territory",
"print_hide": 1,
"report_hide": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Set Item Group-wise budgets on this Territory. You can also include seasonality by setting the Distribution.",
"fetch_if_empty": 0,
"fieldname": "target_details_section_break",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Territory Targets",
"length": 0,
"no_copy": 0,
"oldfieldtype": "Section Break",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"description": "Set Item Group-wise budgets on this Territory. You can also include seasonality by setting the Distribution.",
"fieldname": "target_details_section_break",
"fieldtype": "Section Break",
"label": "Territory Targets",
"oldfieldtype": "Section Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "targets",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Targets",
"length": 0,
"no_copy": 0,
"oldfieldname": "target_details",
"oldfieldtype": "Table",
"options": "Target Detail",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "targets",
"fieldtype": "Table",
"label": "Targets",
"oldfieldname": "target_details",
"oldfieldtype": "Table",
"options": "Target Detail"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-map-marker",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-21 16:26:58.581431",
"modified_by": "Administrator",
"module": "Setup",
"name": "Territory",
"name_case": "Title Case",
"owner": "Administrator",
],
"icon": "fa fa-map-marker",
"idx": 1,
"links": [],
"modified": "2020-01-28 13:49:31.905800",
"modified_by": "Administrator",
"module": "Setup",
"name": "Territory",
"name_case": "Title Case",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 1,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"import": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 1,
"share": 1,
"write": 1
},
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Stock User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
"read": 1,
"role": "Stock User"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Maintenance User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"read": 1,
"role": "Maintenance User"
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "parent_territory,territory_manager",
"show_name_in_global_search": 1,
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
],
"search_fields": "parent_territory,territory_manager",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -162,6 +162,76 @@ class TestLandedCostVoucher(unittest.TestCase):
self.assertEqual(lcv.items[0].applicable_charges, 41.07)
self.assertEqual(lcv.items[2].applicable_charges, 41.08)
def test_multiple_landed_cost_voucher_against_pr(self):
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
supplier_warehouse = "Stores - TCP1", do_not_save=True)
pr.append("items", {
"item_code": "_Test Item",
"warehouse": "Stores - TCP1",
"cost_center": "Main - TCP1",
"qty": 5,
"rate": 100
})
pr.submit()
lcv1 = make_landed_cost_voucher(receipt_document_type = 'Purchase Receipt',
receipt_document=pr.name, charges=100, do_not_save=True)
lcv1.insert()
lcv1.set('items', [
lcv1.get('items')[0]
])
distribute_landed_cost_on_items(lcv1)
lcv1.submit()
lcv2 = make_landed_cost_voucher(receipt_document_type = 'Purchase Receipt',
receipt_document=pr.name, charges=100, do_not_save=True)
lcv2.insert()
lcv2.set('items', [
lcv2.get('items')[1]
])
distribute_landed_cost_on_items(lcv2)
lcv2.submit()
pr.load_from_db()
self.assertEqual(pr.items[0].landed_cost_voucher_amount, 100)
self.assertEqual(pr.items[1].landed_cost_voucher_amount, 100)
def make_landed_cost_voucher(** args):
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
lcv = frappe.new_doc('Landed Cost Voucher')
lcv.company = '_Test Company'
lcv.distribute_charges_based_on = 'Amount'
lcv.set('purchase_receipts', [{
"receipt_document_type": args.receipt_document_type,
"receipt_document": args.receipt_document,
"supplier": ref_doc.supplier,
"posting_date": ref_doc.posting_date,
"grand_total": ref_doc.grand_total
}])
lcv.set("taxes", [{
"description": "Shipping Charges",
"expense_account": "Expenses Included In Valuation - TCP1",
"amount": args.charges
}])
if not args.do_not_save:
lcv.insert()
if not args.do_not_submit:
lcv.submit()
return lcv
def submit_landed_cost_voucher(receipt_document_type, receipt_document, charges=50):
ref_doc = frappe.get_doc(receipt_document_type, receipt_document)

View File

@@ -74,13 +74,13 @@ class PickList(Document):
if item_map.get(key):
item_map[key].qty += item.qty
item_map[key].stock_qty += item.stock_qty
item_map[key].stock_qty += flt(item.stock_qty)
else:
item_map[key] = item
# maintain count of each item (useful to limit get query)
self.item_count_map.setdefault(item_code, 0)
self.item_count_map[item_code] += item.stock_qty
self.item_count_map[item_code] += flt(item.stock_qty)
return item_map.values()

View File

@@ -349,7 +349,7 @@ class PurchaseReceipt(BuyingController):
if warehouse_with_no_account:
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
"\n".join(warehouse_with_no_account))
return process_gl_map(gl_entries)
def get_asset_gl_entry(self, gl_entries):
@@ -616,23 +616,16 @@ def get_item_account_wise_additional_cost(purchase_document):
if not landed_cost_vouchers:
return
total_item_cost = 0
item_account_wise_cost = {}
item_cost_allocated = []
for lcv in landed_cost_vouchers:
landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", lcv.parent)
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
total_item_cost = 0
for item in landed_cost_voucher_doc.items:
if item.purchase_receipt_item not in item_cost_allocated:
total_item_cost += item.get(based_on_field)
item_cost_allocated.append(item.purchase_receipt_item)
for lcv in landed_cost_vouchers:
landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
total_item_cost += item.get(based_on_field)
for item in landed_cost_voucher_doc.items:
if item.receipt_document == purchase_document:

View File

@@ -158,8 +158,11 @@ class TestPurchaseReceipt(unittest.TestCase):
def test_purchase_return_for_rejected_qty(self):
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
rejected_warehouse=get_warehouse(company = "_Test Company with perpetual inventory", abbr = " - TCP1", warehouse_name = "_Test Rejected Warehouse").name
print(rejected_warehouse)
rejected_warehouse="_Test Rejected Warehouse - TCP1"
if not frappe.db.exists("Warehouse", rejected_warehouse):
get_warehouse(company = "_Test Company with perpetual inventory",
abbr = " - TCP1", warehouse_name = "_Test Rejected Warehouse").name
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", received_qty=4, qty=2, rejected_warehouse=rejected_warehouse)
return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, received_qty = -4, qty=-2, rejected_warehouse=rejected_warehouse)
@@ -262,6 +265,30 @@ class TestPurchaseReceipt(unittest.TestCase):
self.assertEqual(pr2.per_billed, 80)
self.assertEqual(pr2.status, "To Bill")
def test_serial_no_against_purchase_receipt(self):
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
item_code = "Test Manual Created Serial No"
if not frappe.db.exists("Item", item_code):
item = make_item(item_code, dict(has_serial_no=1))
serial_no = "12903812901"
pr_doc = make_purchase_receipt(item_code=item_code,
qty=1, serial_no = serial_no)
self.assertEqual(serial_no, frappe.db.get_value("Serial No",
{"purchase_document_type": "Purchase Receipt", "purchase_document_no": pr_doc.name}, "name"))
item_code = "Test Auto Created Serial No"
if not frappe.db.exists("Item", item_code):
item = make_item(item_code, dict(has_serial_no=1, serial_no_series="KLJL.###"))
new_pr_doc = make_purchase_receipt(item_code=item_code, qty=1)
serial_no = get_serial_nos(new_pr_doc.items[0].serial_no)[0]
self.assertEqual(serial_no, frappe.db.get_value("Serial No",
{"purchase_document_type": "Purchase Receipt", "purchase_document_no": new_pr_doc.name}, "name"))
def test_not_accept_duplicate_serial_no(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note

View File

@@ -29,13 +29,12 @@ class SerialNo(StockController):
self.via_stock_ledger = False
def validate(self):
if self.get("__islocal") and self.warehouse:
if self.get("__islocal") and self.warehouse and not self.via_stock_ledger:
frappe.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError)
self.set_maintenance_status()
self.validate_warehouse()
self.validate_item()
self.on_stock_ledger_entry()
def set_maintenance_status(self):
if not self.warranty_expiry_date and not self.amc_expiry_date:
@@ -68,7 +67,7 @@ class SerialNo(StockController):
"""
Validate whether serial no is required for this item
"""
item = frappe.get_doc("Item", self.item_code)
item = frappe.get_cached_doc("Item", self.item_code)
if item.has_serial_no!=1:
frappe.throw(_("Item {0} is not setup for Serial Nos. Check Item master").format(self.item_code))
@@ -117,9 +116,9 @@ class SerialNo(StockController):
"warranty_expiry_date"):
self.set(fieldname, None)
def get_last_sle(self):
def get_last_sle(self, serial_no=None):
entries = {}
sle_dict = self.get_stock_ledger_entries()
sle_dict = self.get_stock_ledger_entries(serial_no)
if sle_dict:
if sle_dict.get("incoming", []):
entries["purchase_sle"] = sle_dict["incoming"][0]
@@ -132,13 +131,28 @@ class SerialNo(StockController):
return entries
def get_stock_ledger_entries(self):
def get_stock_ledger_entries(self, serial_no=None):
sle_dict = {}
for sle in frappe.db.sql("""select * from `tabStock Ledger Entry`
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'
order by posting_date desc, posting_time desc, creation desc""",
("%%%s%%" % self.name, self.item_code), as_dict=1):
if self.name.upper() in get_serial_nos(sle.serial_no):
if not serial_no:
serial_no = self.name
for sle in frappe.db.sql("""
SELECT voucher_type, voucher_no,
posting_date, posting_time, incoming_rate, actual_qty, serial_no
FROM
`tabStock Ledger Entry`
WHERE
item_code=%s AND company = %s AND ifnull(is_cancelled, 'No')='No'
AND (serial_no = %s
OR serial_no like %s
OR serial_no like %s
OR serial_no like %s
)
ORDER BY
posting_date desc, posting_time desc, creation desc""",
(self.item_code, self.company,
serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'), as_dict=1):
if serial_no.upper() in get_serial_nos(sle.serial_no):
if cint(sle.actual_qty) > 0:
sle_dict.setdefault("incoming", []).append(sle)
else:
@@ -178,12 +192,11 @@ class SerialNo(StockController):
where name=%s""" % (dt[0], '%s', '%s'),
('\n'.join(list(serial_nos)), item[0]))
def on_stock_ledger_entry(self):
if self.via_stock_ledger and not self.get("__islocal"):
last_sle = self.get_last_sle()
self.set_purchase_details(last_sle.get("purchase_sle"))
self.set_sales_details(last_sle.get("delivery_sle"))
self.set_maintenance_status()
def update_serial_no_reference(self, serial_no=None):
last_sle = self.get_last_sle(serial_no)
self.set_purchase_details(last_sle.get("purchase_sle"))
self.set_sales_details(last_sle.get("delivery_sle"))
self.set_maintenance_status()
def process_serial_no(sle):
item_det = get_item_details(sle.item_code)
@@ -366,6 +379,7 @@ def auto_make_serial_nos(args):
if sr.sales_order and args.get('voucher_type') == "Stock Entry" \
and not args.get('actual_qty', 0) > 0:
sr.sales_order = None
sr.update_serial_no_reference()
sr.save(ignore_permissions=True)
elif args.get('actual_qty', 0) > 0:
created_numbers.append(make_serial_no(serial_no, args))
@@ -387,27 +401,16 @@ def get_serial_nos(serial_no):
def make_serial_no(serial_no, args):
sr = frappe.new_doc("Serial No")
sr.warehouse = None
sr.dont_update_if_missing.append("warehouse")
sr.flags.ignore_permissions = True
sr.serial_no = serial_no
sr.item_code = args.get('item_code')
sr.company = args.get('company')
sr.batch_no = args.get('batch_no')
sr.via_stock_ledger = args.get('via_stock_ledger') or True
sr.asset = args.get('asset')
sr.location = args.get('location')
sr.warehouse = args.get('warehouse')
if args.get('purchase_document_type'):
sr.purchase_document_type = args.get('purchase_document_type')
sr.purchase_document_no = args.get('purchase_document_no')
sr.supplier = args.get('supplier')
sr.insert()
if args.get('warehouse'):
sr.warehouse = args.get('warehouse')
sr.save()
sr.validate_item()
sr.update_serial_no_reference(serial_no)
sr.db_insert()
return sr.name
@@ -474,10 +477,11 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note):
return serial_nos
@frappe.whitelist()
def auto_fetch_serial_number(qty, item_code, warehouse):
def auto_fetch_serial_number(qty, item_code, warehouse, batch_no=None):
serial_numbers = frappe.get_list("Serial No", filters={
"item_code": item_code,
"warehouse": warehouse,
"batch_no": batch_no,
"delivery_document_no": "",
"sales_invoice": ""
}, limit=qty, order_by="creation")

View File

@@ -1056,7 +1056,7 @@ class StockEntry(StockController):
req_qty_each = flt(req_qty / manufacturing_qty)
consumed_qty = flt(req_items[0].consumed_qty)
if trans_qty and manufacturing_qty >= (produced_qty + flt(self.fg_completed_qty)):
if trans_qty and manufacturing_qty > (produced_qty + flt(self.fg_completed_qty)):
if qty >= req_qty:
qty = (req_qty/trans_qty) * flt(self.fg_completed_qty)
else:

View File

@@ -1,10 +1,12 @@
{
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"creation": "2013-03-07 18:50:32",
"description": "A logical Warehouse against which stock entries are made.",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"warehouse_detail",
"warehouse_name",
@@ -226,7 +228,8 @@
],
"icon": "fa fa-building",
"idx": 1,
"modified": "2019-05-22 11:17:23.357490",
"links": [],
"modified": "2020-01-28 13:50:59.368846",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",
@@ -279,8 +282,8 @@
"role": "Manufacturing User"
}
],
"quick_entry": 1,
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "warehouse_name"
}

View File

@@ -1,10 +1,10 @@
braintree==3.57.1
frappe
unidecode
pygithub
googlemaps
python-stdnum
braintree
gocardless_pro
woocommerce
pandas
plaid-python
gocardless-pro==1.11.0
googlemaps==3.1.1
pandas==0.24.2
plaid-python==3.4.0
PyGithub==1.44.1
python-stdnum==1.12
Unidecode==1.1.1
WooCommerce==2.1.1