mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-14 20:35:09 +00:00
Merge branch 'version-12-hotfix' into rcm_version-12-hotfix
This commit is contained in:
@@ -14,6 +14,9 @@ frappe.treeview_settings["Account"] = {
|
||||
on_change: function() {
|
||||
var me = frappe.treeview_settings['Account'].treeview;
|
||||
var company = me.page.fields_dict.company.get_value();
|
||||
if (!company) {
|
||||
frappe.throw(__("Please set a Company"));
|
||||
}
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||
args: {
|
||||
|
||||
@@ -41,10 +41,16 @@ def get_loyalty_program_details_with_points(customer, loyalty_program=None, expi
|
||||
loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program)
|
||||
lp_details.update(get_loyalty_details(customer, loyalty_program.name, expiry_date, company, include_expired_entry))
|
||||
|
||||
tier_spent_level = sorted([d.as_dict() for d in loyalty_program.collection_rules],
|
||||
key=lambda rule:rule.min_spent, reverse=True)
|
||||
# sort collection rule, first item on list will be lowest min_spent
|
||||
tier_spent_level = sorted(
|
||||
[d.as_dict() for d in loyalty_program.collection_rules],
|
||||
key=lambda rule: rule.min_spent, reverse=False,
|
||||
)
|
||||
|
||||
# looping and apply tier from lowest min_spent
|
||||
for i, d in enumerate(tier_spent_level):
|
||||
if i==0 or (lp_details.total_spent+current_transaction_amount) <= d.min_spent:
|
||||
# if cumulative spend more than min_spent then continue to next tier
|
||||
if (lp_details.total_spent + current_transaction_amount) >= d.min_spent:
|
||||
lp_details.tier_name = d.tier_name
|
||||
lp_details.collection_factor = d.collection_factor
|
||||
else:
|
||||
|
||||
@@ -68,6 +68,7 @@ class TestLoyaltyProgram(unittest.TestCase):
|
||||
|
||||
lpe = frappe.get_doc('Loyalty Point Entry', {'sales_invoice': si_original.name, 'customer': si_original.customer})
|
||||
|
||||
customer.load_from_db()
|
||||
self.assertEqual(si_original.get('loyalty_program'), customer.loyalty_program)
|
||||
self.assertEqual(lpe.get('loyalty_program_tier'), customer.loyalty_program_tier)
|
||||
self.assertEqual(lpe.loyalty_points, earned_points)
|
||||
|
||||
@@ -318,7 +318,7 @@ class PaymentEntry(AccountsController):
|
||||
invoice_payment_amount_map.setdefault(key, 0.0)
|
||||
invoice_payment_amount_map[key] += reference.allocated_amount
|
||||
|
||||
if not invoice_paid_amount_map.get(reference.reference_name):
|
||||
if not invoice_paid_amount_map.get(key):
|
||||
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
|
||||
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
||||
for term in payment_schedule:
|
||||
@@ -331,12 +331,14 @@ class PaymentEntry(AccountsController):
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
else:
|
||||
outstanding = invoice_paid_amount_map.get(key)['outstanding']
|
||||
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
|
||||
|
||||
if amount > outstanding:
|
||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
||||
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
if amount and outstanding:
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
|
||||
def set_status(self):
|
||||
if self.docstatus == 2:
|
||||
@@ -1090,17 +1092,20 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||
references = []
|
||||
for payment_term in payment_schedule:
|
||||
references.append({
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
'bill_no': doc.get('bill_no'),
|
||||
'due_date': doc.get('due_date'),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||
payment_term_outstanding = flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||
payment_term.precision('payment_amount'))
|
||||
})
|
||||
|
||||
if payment_term_outstanding:
|
||||
references.append({
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
'bill_no': doc.get('bill_no'),
|
||||
'due_date': doc.get('due_date'),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': payment_term_outstanding
|
||||
})
|
||||
|
||||
return references
|
||||
|
||||
|
||||
@@ -385,6 +385,50 @@ class TestPricingRule(unittest.TestCase):
|
||||
so.load_from_db()
|
||||
self.assertEqual(so.items[1].is_free_item, 1)
|
||||
self.assertEqual(so.items[1].item_code, "_Test Item 2")
|
||||
|
||||
def test_cumulative_pricing_rule(self):
|
||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Cumulative Pricing Rule')
|
||||
test_record = {
|
||||
"doctype": "Pricing Rule",
|
||||
"title": "_Test Cumulative Pricing Rule",
|
||||
"apply_on": "Item Code",
|
||||
"currency": "USD",
|
||||
"items": [{
|
||||
"item_code": "_Test Item",
|
||||
}],
|
||||
"is_cumulative": 1,
|
||||
"selling": 1,
|
||||
"applicable_for": "Customer",
|
||||
"customer": "_Test Customer",
|
||||
"rate_or_discount": "Discount Percentage",
|
||||
"rate": 0,
|
||||
"min_amt": 0,
|
||||
"max_amt": 10000,
|
||||
"discount_percentage": 17.5,
|
||||
"price_or_product_discount": "Price",
|
||||
"company": "_Test Company",
|
||||
"valid_from": frappe.utils.nowdate(),
|
||||
"valid_upto": frappe.utils.nowdate()
|
||||
}
|
||||
frappe.get_doc(test_record.copy()).insert()
|
||||
|
||||
args = frappe._dict({
|
||||
"item_code": "_Test Item",
|
||||
"company": "_Test Company",
|
||||
"price_list": "_Test Price List",
|
||||
"currency": "_Test Currency",
|
||||
"doctype": "Sales Invoice",
|
||||
"conversion_rate": 1,
|
||||
"price_list_currency": "_Test Currency",
|
||||
"plc_conversion_rate": 1,
|
||||
"order_type": "Sales",
|
||||
"customer": "_Test Customer",
|
||||
"name": None,
|
||||
"transaction_date": frappe.utils.nowdate()
|
||||
})
|
||||
details = get_item_details(args)
|
||||
|
||||
self.assertTrue(details)
|
||||
|
||||
def make_pricing_rule(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
@@ -13,7 +13,10 @@ from six import string_types
|
||||
import frappe
|
||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
from erpnext.stock.get_item_details import get_conversion_factor
|
||||
from erpnext.stock.get_item_details import get_conversion_factor, get_default_income_account
|
||||
from erpnext.stock.doctype.item.item import get_item_defaults
|
||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||
from erpnext.setup.doctype.brand.brand import get_brand_defaults
|
||||
from frappe import _, throw
|
||||
from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
|
||||
|
||||
@@ -366,8 +369,7 @@ def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
|
||||
sum_qty, sum_amt = [0, 0]
|
||||
doctype = doc.get('parenttype') or doc.doctype
|
||||
|
||||
date_field = ('transaction_date'
|
||||
if doc.get('transaction_date') else 'posting_date')
|
||||
date_field = 'transaction_date' if frappe.get_meta(doctype).has_field('transaction_date') else 'posting_date'
|
||||
|
||||
child_doctype = '{0} Item'.format(doctype)
|
||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
||||
@@ -481,6 +483,14 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
||||
if item_details.get("parenttype") == 'Sales Order':
|
||||
item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
|
||||
|
||||
company = args.get('company') or doc.company
|
||||
item_details.free_item_data['income_account'] = get_default_income_account(
|
||||
args=args,
|
||||
item=get_item_defaults(free_item, company),
|
||||
item_group=get_item_group_defaults(free_item, company),
|
||||
brand=get_brand_defaults(free_item, company),
|
||||
)
|
||||
|
||||
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||
if pricing_rule_args.get('item_code'):
|
||||
items = [d.item_code for d in doc.items
|
||||
|
||||
@@ -552,6 +552,8 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for d in self.get('items'):
|
||||
if not d.item_code: continue
|
||||
|
||||
is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item')
|
||||
if (d.item_code and is_stock_item ==1 and not d.get(key.lower().replace(' ', '_')) and not self.get(value[1])):
|
||||
msgprint(_("{0} is mandatory for Item {1}").format(key, d.item_code), raise_exception=1)
|
||||
@@ -574,14 +576,14 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def validate_item_code(self):
|
||||
for d in self.get('items'):
|
||||
if not d.item_code:
|
||||
if not d.item_code and self.is_opening == "No":
|
||||
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
|
||||
|
||||
def validate_warehouse(self):
|
||||
super(SalesInvoice, self).validate_warehouse()
|
||||
|
||||
for d in self.get_item_list():
|
||||
if not d.warehouse and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||
if not d.warehouse and d.item_code and frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
||||
|
||||
def validate_delivery_note(self):
|
||||
|
||||
@@ -45,7 +45,9 @@ class ShippingRule(Document):
|
||||
shipping_amount = 0.0
|
||||
by_value = False
|
||||
|
||||
self.validate_countries(doc)
|
||||
if doc.get_shipping_address():
|
||||
# validate country only if there is address
|
||||
self.validate_countries(doc)
|
||||
|
||||
if self.calculate_based_on == 'Net Total':
|
||||
value = doc.base_net_total
|
||||
|
||||
@@ -58,7 +58,7 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
|
||||
"rate": tax_rate_detail.tax_withholding_rate,
|
||||
"threshold": tax_rate_detail.single_threshold,
|
||||
"cumulative_threshold": tax_rate_detail.cumulative_threshold,
|
||||
"description": tax_withholding.category_name
|
||||
"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
|
||||
})
|
||||
|
||||
def get_tax_withholding_rates(tax_withholding, fiscal_year):
|
||||
@@ -225,4 +225,4 @@ def is_valid_certificate(valid_from, valid_upto, posting_date, deducted_amount,
|
||||
certificate_limit > deducted_amount):
|
||||
valid = True
|
||||
|
||||
return valid
|
||||
return valid
|
||||
|
||||
@@ -169,9 +169,11 @@ class ReceivablePayableReport(object):
|
||||
|
||||
def append_subtotal_row(self, party):
|
||||
sub_total_row = self.total_row_map.get(party)
|
||||
self.data.append(sub_total_row)
|
||||
self.data.append({})
|
||||
self.update_sub_total_row(sub_total_row, 'Total')
|
||||
|
||||
if sub_total_row:
|
||||
self.data.append(sub_total_row)
|
||||
self.data.append({})
|
||||
self.update_sub_total_row(sub_total_row, 'Total')
|
||||
|
||||
def get_voucher_balance(self, gle):
|
||||
if self.filters.get("sales_person"):
|
||||
@@ -232,7 +234,8 @@ class ReceivablePayableReport(object):
|
||||
|
||||
if self.filters.get('group_by_party'):
|
||||
self.append_subtotal_row(self.previous_party)
|
||||
self.data.append(self.total_row_map.get('Total'))
|
||||
if self.data:
|
||||
self.data.append(self.total_row_map.get('Total'))
|
||||
|
||||
def append_row(self, row):
|
||||
self.allocate_future_payments(row)
|
||||
|
||||
@@ -93,7 +93,7 @@ def get_assets(filters):
|
||||
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
||||
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
||||
from (SELECT a.asset_category,
|
||||
ifnull(sum(case when ds.schedule_date < %(from_date)s then
|
||||
ifnull(sum(case when ds.schedule_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
|
||||
ds.depreciation_amount
|
||||
else
|
||||
0
|
||||
@@ -115,9 +115,7 @@ def get_assets(filters):
|
||||
group by a.asset_category
|
||||
union
|
||||
SELECT a.asset_category,
|
||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||
and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s)
|
||||
then
|
||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
|
||||
0
|
||||
else
|
||||
a.opening_accumulated_depreciation
|
||||
|
||||
@@ -50,9 +50,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_v
|
||||
to_date = add_months(start_date, months_to_add)
|
||||
start_date = to_date
|
||||
|
||||
if to_date == get_first_day(to_date):
|
||||
# if to_date is the first day, get the last day of previous month
|
||||
to_date = add_days(to_date, -1)
|
||||
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||
to_date = add_days(to_date, -1)
|
||||
|
||||
if to_date <= year_end_date:
|
||||
# the normal case
|
||||
|
||||
@@ -126,6 +126,8 @@ class Asset(AccountsController):
|
||||
frappe.throw(_("Available-for-use Date should be after purchase date"))
|
||||
|
||||
def validate_gross_and_purchase_amount(self):
|
||||
if self.is_existing_asset: return
|
||||
|
||||
if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount:
|
||||
frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\
|
||||
Please do not book expense of multiple assets against one single Asset.")
|
||||
|
||||
@@ -1,559 +1,140 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:asset_name",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-19 16:50:22.879545",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"autoname": "field:asset_name",
|
||||
"creation": "2017-10-19 16:50:22.879545",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"asset_name",
|
||||
"asset_category",
|
||||
"company",
|
||||
"column_break_3",
|
||||
"item_code",
|
||||
"item_name",
|
||||
"section_break_6",
|
||||
"maintenance_team",
|
||||
"column_break_9",
|
||||
"maintenance_manager",
|
||||
"maintenance_manager_name",
|
||||
"section_break_8",
|
||||
"asset_maintenance_tasks"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "asset_name",
|
||||
"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": "Asset Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Asset",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "asset_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Asset Name",
|
||||
"options": "Asset",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_name.asset_category",
|
||||
"fieldname": "asset_category",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Asset Category",
|
||||
"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
|
||||
},
|
||||
"fieldname": "asset_category",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Asset Category"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_name.item_code",
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Item Code",
|
||||
"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
|
||||
},
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Item Code"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_name.item_name",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Item Name",
|
||||
"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
|
||||
},
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Item Name"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"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": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "select_serial_no",
|
||||
"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": "Select Serial No",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Serial No",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"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": "Serial No",
|
||||
"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
|
||||
},
|
||||
"fieldname": "maintenance_team",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Maintenance Team",
|
||||
"options": "Asset Maintenance Team",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "maintenance_team",
|
||||
"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": "Maintenance Team",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Asset Maintenance Team",
|
||||
"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": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"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
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "maintenance_team.maintenance_manager",
|
||||
"fieldname": "maintenance_manager",
|
||||
"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": "Maintenance Manager",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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
|
||||
},
|
||||
"fieldname": "maintenance_manager",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Maintenance Manager",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "maintenance_team.maintenance_manager_name",
|
||||
"fieldname": "maintenance_manager_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Maintenance Manager Name",
|
||||
"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
|
||||
},
|
||||
"fieldname": "maintenance_manager_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Maintenance Manager Name"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"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": "Tasks",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Tasks"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "asset_maintenance_tasks",
|
||||
"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": "Maintenance Tasks",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Asset Maintenance Task",
|
||||
"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": 0
|
||||
"fieldname": "asset_maintenance_tasks",
|
||||
"fieldtype": "Table",
|
||||
"label": "Maintenance Tasks",
|
||||
"options": "Asset Maintenance Task",
|
||||
"reqd": 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-05-22 17:20:54.711885",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Maintenance",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-05-28 20:28:32.993823",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Maintenance",
|
||||
"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": "Quality Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Quality Manager",
|
||||
"share": 1,
|
||||
"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": "Manufacturing User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Manufacturing User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class AssetMaintenance(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def assign_tasks(asset_maintenance_name, assign_to_member, maintenance_task, next_due_date):
|
||||
team_member = frappe.get_doc('User', assign_to_member).email
|
||||
team_member = frappe.db.get_value('User', assign_to_member, "email")
|
||||
args = {
|
||||
'doctype' : 'Asset Maintenance',
|
||||
'assign_to' : team_member,
|
||||
@@ -78,7 +78,7 @@ def calculate_next_due_date(periodicity, start_date = None, end_date = None, las
|
||||
|
||||
def update_maintenance_log(asset_maintenance, item_code, item_name, task):
|
||||
asset_maintenance_log = frappe.get_value("Asset Maintenance Log", {"asset_maintenance": asset_maintenance,
|
||||
"task": task.maintenance_task, "maintenance_status": ('in',['Planned','Overdue'])})
|
||||
"task": task.name, "maintenance_status": ('in',['Planned','Overdue'])})
|
||||
|
||||
if not asset_maintenance_log:
|
||||
asset_maintenance_log = frappe.get_doc({
|
||||
@@ -87,7 +87,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
|
||||
"asset_name": asset_maintenance,
|
||||
"item_code": item_code,
|
||||
"item_name": item_name,
|
||||
"task": task.maintenance_task,
|
||||
"task": task.name,
|
||||
"has_certificate": task.certificate_required,
|
||||
"description": task.description,
|
||||
"assign_to_name": task.assign_to_name,
|
||||
|
||||
@@ -1,819 +1,210 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-23 16:58:44.424309",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2017-10-23 16:58:44.424309",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"asset_maintenance",
|
||||
"naming_series",
|
||||
"asset_name",
|
||||
"column_break_2",
|
||||
"item_code",
|
||||
"item_name",
|
||||
"section_break_5",
|
||||
"task",
|
||||
"task_name",
|
||||
"maintenance_type",
|
||||
"periodicity",
|
||||
"assign_to_name",
|
||||
"column_break_6",
|
||||
"due_date",
|
||||
"completion_date",
|
||||
"maintenance_status",
|
||||
"section_break_12",
|
||||
"has_certificate",
|
||||
"certificate_attachement",
|
||||
"section_break_6",
|
||||
"description",
|
||||
"column_break_9",
|
||||
"actions_performed",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "asset_maintenance",
|
||||
"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": "Asset Maintenance",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Asset Maintenance",
|
||||
"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
|
||||
},
|
||||
"fieldname": "asset_maintenance",
|
||||
"fieldtype": "Link",
|
||||
"label": "Asset Maintenance",
|
||||
"options": "Asset Maintenance"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"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": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "ACC-AML-.YYYY.-",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"options": "ACC-AML-.YYYY.-",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_maintenance.asset_name",
|
||||
"fieldname": "asset_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Asset Name",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "asset_maintenance.asset_name",
|
||||
"fieldname": "asset_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Asset Name"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_maintenance.item_code",
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Item Code",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "asset_maintenance.item_code",
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Item Code"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "asset_maintenance.item_name",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Item Name",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "asset_maintenance.item_name",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Item Name"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "task",
|
||||
"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": "Task",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Asset Maintenance Task",
|
||||
"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
|
||||
},
|
||||
"fieldname": "task",
|
||||
"fieldtype": "Link",
|
||||
"label": "Task",
|
||||
"options": "Asset Maintenance Task"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.maintenance_type",
|
||||
"fieldname": "maintenance_type",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Maintenance Type",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "task.maintenance_type",
|
||||
"fieldname": "maintenance_type",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Maintenance Type"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.periodicity",
|
||||
"fieldname": "periodicity",
|
||||
"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": "Periodicity",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "task.periodicity",
|
||||
"fieldname": "periodicity",
|
||||
"fieldtype": "Data",
|
||||
"label": "Periodicity",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.assign_to_name",
|
||||
"fieldname": "assign_to_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Assign To",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "task.assign_to_name",
|
||||
"fieldname": "assign_to_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Assign To"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_6",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.next_due_date",
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "task.next_due_date",
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Due Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "completion_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Completion Date",
|
||||
"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
|
||||
},
|
||||
"fieldname": "completion_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Completion Date"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "maintenance_status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Maintenance Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Planned\nCompleted\nCancelled\nOverdue",
|
||||
"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": 0
|
||||
},
|
||||
"fieldname": "maintenance_status",
|
||||
"fieldtype": "Select",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Maintenance Status",
|
||||
"options": "Planned\nCompleted\nCancelled\nOverdue",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_12",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_12",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.certificate_required",
|
||||
"fieldname": "has_certificate",
|
||||
"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": "Has Certificate ",
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fetch_from": "task.certificate_required",
|
||||
"fieldname": "has_certificate",
|
||||
"fieldtype": "Check",
|
||||
"label": "Has Certificate "
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.has_certificate",
|
||||
"fieldname": "certificate_attachement",
|
||||
"fieldtype": "Attach",
|
||||
"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": "Certificate",
|
||||
"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
|
||||
},
|
||||
"depends_on": "eval:doc.has_certificate",
|
||||
"fieldname": "certificate_attachement",
|
||||
"fieldtype": "Attach",
|
||||
"label": "Certificate"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "task.description",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Read Only",
|
||||
"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": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "task.description",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Description",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "actions_performed",
|
||||
"fieldtype": "Text Editor",
|
||||
"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": "Actions performed",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "actions_performed",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Actions performed"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"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": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Asset Maintenance Log",
|
||||
"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
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Asset Maintenance Log",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "task.maintenance_task",
|
||||
"fieldname": "task_name",
|
||||
"fieldtype": "Data",
|
||||
"in_preview": 1,
|
||||
"label": "Task Name",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-21 14:44:51.457835",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Maintenance Log",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-28 20:51:48.238397",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Maintenance Log",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Manufacturing User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Manufacturing User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "",
|
||||
"track_changes": 1,
|
||||
"track_seen": 1,
|
||||
"track_views": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 1
|
||||
}
|
||||
@@ -7,5 +7,4 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AssetMaintenanceTask(Document):
|
||||
def autoname(self):
|
||||
self.name = self.maintenance_task
|
||||
pass
|
||||
|
||||
@@ -1056,7 +1056,7 @@
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-17 13:04:28.185197",
|
||||
"modified": "2020-06-12 14:08:11.777120",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
@@ -1100,6 +1100,12 @@
|
||||
"read": 1,
|
||||
"role": "Purchase Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "Accounts User"
|
||||
}
|
||||
],
|
||||
"search_fields": "status, transaction_date, supplier,grand_total",
|
||||
|
||||
@@ -71,6 +71,15 @@ class PurchaseOrder(BuyingController):
|
||||
"compare_fields": [["project", "="], ["item_code", "="],
|
||||
["uom", "="], ["conversion_factor", "="]],
|
||||
"is_child_table": True
|
||||
},
|
||||
"Material Request": {
|
||||
"ref_dn_field": "material_request",
|
||||
"compare_fields": [["company", "="]],
|
||||
},
|
||||
"Material Request Item": {
|
||||
"ref_dn_field": "material_request_item",
|
||||
"compare_fields": [["project", "="], ["item_code", "="]],
|
||||
"is_child_table": True
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
self.assertEqual(po.get("items")[0].amount, 1400)
|
||||
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
|
||||
|
||||
|
||||
|
||||
def test_add_new_item_in_update_child_qty_rate(self):
|
||||
po = create_purchase_order(do_not_save=1)
|
||||
po.items[0].qty = 4
|
||||
@@ -142,7 +142,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
self.assertEquals(len(po.get('items')), 2)
|
||||
self.assertEqual(po.status, 'To Receive and Bill')
|
||||
|
||||
|
||||
|
||||
def test_remove_item_in_update_child_qty_rate(self):
|
||||
po = create_purchase_order(do_not_save=1)
|
||||
po.items[0].qty = 4
|
||||
@@ -183,6 +183,23 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
self.assertEquals(len(po.get('items')), 1)
|
||||
self.assertEqual(po.status, 'To Receive and Bill')
|
||||
|
||||
def test_update_child_qty_rate_perm(self):
|
||||
po = create_purchase_order(item_code= "_Test Item", qty=4)
|
||||
|
||||
user = 'test@example.com'
|
||||
test_user = frappe.get_doc('User', user)
|
||||
test_user.add_roles("Accounts User")
|
||||
frappe.set_user(user)
|
||||
|
||||
# update qty
|
||||
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.items[0].name}])
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Purchase Order', trans_item, po.name)
|
||||
|
||||
# add new item
|
||||
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 100, 'qty' : 2}])
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Purchase Order', trans_item, po.name)
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_update_qty(self):
|
||||
po = create_purchase_order()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns(filters)
|
||||
@@ -54,15 +55,16 @@ def get_columns(filters):
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"label": _("Description"),
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Data",
|
||||
"width": 200
|
||||
"label": _("Item"),
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"options": "Item",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"label": _("Quantity"),
|
||||
"fieldname": "quantity",
|
||||
"fieldtype": "Int",
|
||||
"fieldtype": "Float",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
@@ -118,7 +120,7 @@ def get_columns(filters):
|
||||
},
|
||||
{
|
||||
"label": _("Purchase Order Amount(Company Currency)"),
|
||||
"fieldname": "purchase_order_amt_usd",
|
||||
"fieldname": "purchase_order_amt_in_company_currency",
|
||||
"fieldtype": "Float",
|
||||
"width": 140
|
||||
},
|
||||
@@ -175,17 +177,17 @@ def get_data(filters):
|
||||
"requesting_site": po.warehouse,
|
||||
"requestor": po.owner,
|
||||
"material_request_no": po.material_request,
|
||||
"description": po.description,
|
||||
"quantity": po.qty,
|
||||
"item_code": po.item_code,
|
||||
"quantity": flt(po.qty),
|
||||
"unit_of_measurement": po.stock_uom,
|
||||
"status": po.status,
|
||||
"purchase_order_date": po.transaction_date,
|
||||
"purchase_order": po.parent,
|
||||
"supplier": po.supplier,
|
||||
"estimated_cost": mr_record.get('amount'),
|
||||
"actual_cost": pi_records.get(po.name),
|
||||
"purchase_order_amt": po.amount,
|
||||
"purchase_order_amt_in_company_currency": po.base_amount,
|
||||
"estimated_cost": flt(mr_record.get('amount')),
|
||||
"actual_cost": flt(pi_records.get(po.name)),
|
||||
"purchase_order_amt": flt(po.amount),
|
||||
"purchase_order_amt_in_company_currency": flt(po.base_amount),
|
||||
"expected_delivery_date": po.schedule_date,
|
||||
"actual_delivery_date": pr_records.get(po.name)
|
||||
}
|
||||
@@ -198,9 +200,14 @@ def get_mapped_mr_details(conditions):
|
||||
SELECT
|
||||
par.transaction_date,
|
||||
par.per_ordered,
|
||||
par.owner,
|
||||
child.name,
|
||||
child.parent,
|
||||
child.amount
|
||||
child.amount,
|
||||
child.qty,
|
||||
child.item_code,
|
||||
child.uom,
|
||||
par.status
|
||||
FROM `tabMaterial Request` par, `tabMaterial Request Item` child
|
||||
WHERE
|
||||
par.per_ordered>=0
|
||||
@@ -217,7 +224,15 @@ def get_mapped_mr_details(conditions):
|
||||
procurement_record_details = dict(
|
||||
material_request_date=record.transaction_date,
|
||||
material_request_no=record.parent,
|
||||
estimated_cost=record.amount
|
||||
requestor=record.owner,
|
||||
item_code=record.item_code,
|
||||
estimated_cost=flt(record.amount),
|
||||
quantity=flt(record.qty),
|
||||
unit_of_measurement=record.uom,
|
||||
status=record.status,
|
||||
actual_cost=0,
|
||||
purchase_order_amt=0,
|
||||
purchase_order_amt_in_company_currency=0
|
||||
)
|
||||
procurement_record_against_mr.append(procurement_record_details)
|
||||
return mr_records, procurement_record_against_mr
|
||||
@@ -259,7 +274,7 @@ def get_po_entries(conditions):
|
||||
child.warehouse,
|
||||
child.material_request,
|
||||
child.material_request_item,
|
||||
child.description,
|
||||
child.item_code,
|
||||
child.stock_uom,
|
||||
child.qty,
|
||||
child.amount,
|
||||
|
||||
@@ -15,7 +15,7 @@ class TestProcurementTracker(unittest.TestCase):
|
||||
def test_result_for_procurement_tracker(self):
|
||||
filters = {
|
||||
'company': '_Test Procurement Company',
|
||||
'cost_center': '_Test Cost Center - _TC'
|
||||
'cost_center': 'Main - _TPC'
|
||||
}
|
||||
expected_data = self.generate_expected_data()
|
||||
report = execute(filters)
|
||||
@@ -33,24 +33,27 @@ class TestProcurementTracker(unittest.TestCase):
|
||||
country="Pakistan"
|
||||
)).insert()
|
||||
warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
|
||||
mr = make_material_request(company="_Test Procurement Company", warehouse=warehouse)
|
||||
mr = make_material_request(company="_Test Procurement Company", warehouse=warehouse, cost_center="Main - _TPC")
|
||||
po = make_purchase_order(mr.name)
|
||||
po.supplier = "_Test Supplier"
|
||||
po.get("items")[0].cost_center = "_Test Cost Center - _TC"
|
||||
po.get("items")[0].cost_center = "Main - _TPC"
|
||||
po.submit()
|
||||
pr = make_purchase_receipt(po.name)
|
||||
pr.get("items")[0].cost_center = "Main - _TPC"
|
||||
pr.submit()
|
||||
frappe.db.commit()
|
||||
date_obj = datetime.date(datetime.now())
|
||||
|
||||
po.load_from_db()
|
||||
|
||||
expected_data = {
|
||||
"material_request_date": date_obj,
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"cost_center": "Main - _TPC",
|
||||
"project": None,
|
||||
"requesting_site": "_Test Procurement Warehouse - _TPC",
|
||||
"requestor": "Administrator",
|
||||
"material_request_no": mr.name,
|
||||
"description": '_Test Item 1',
|
||||
"item_code": '_Test Item',
|
||||
"quantity": 10.0,
|
||||
"unit_of_measurement": "_Test UOM",
|
||||
"status": "To Bill",
|
||||
@@ -58,9 +61,9 @@ class TestProcurementTracker(unittest.TestCase):
|
||||
"purchase_order": po.name,
|
||||
"supplier": "_Test Supplier",
|
||||
"estimated_cost": 0.0,
|
||||
"actual_cost": None,
|
||||
"purchase_order_amt": 5000.0,
|
||||
"purchase_order_amt_in_company_currency": 300000.0,
|
||||
"actual_cost": 0.0,
|
||||
"purchase_order_amt": po.net_total,
|
||||
"purchase_order_amt_in_company_currency": po.base_net_total,
|
||||
"expected_delivery_date": date_obj,
|
||||
"actual_delivery_date": date_obj
|
||||
}
|
||||
|
||||
@@ -1134,8 +1134,8 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
|
||||
child_item.item_name = item.item_name
|
||||
child_item.description = item.description
|
||||
child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
|
||||
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||
child_item.uom = item.stock_uom
|
||||
child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||
if not child_item.warehouse:
|
||||
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
||||
@@ -1154,8 +1154,8 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
|
||||
child_item.item_name = item.item_name
|
||||
child_item.description = item.description
|
||||
child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
|
||||
child_item.conversion_factor = flt(trans_item.get('conversion_factor')) or get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||
child_item.uom = item.stock_uom
|
||||
child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
||||
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||
return child_item
|
||||
@@ -1178,7 +1178,7 @@ def check_and_delete_children(parent, data):
|
||||
|
||||
if parent.doctype == "Purchase Order" and flt(d.received_qty):
|
||||
frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been received").format(d.idx, d.item_code))
|
||||
|
||||
|
||||
if flt(d.billed_amt):
|
||||
frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been billed.").format(d.idx, d.item_code))
|
||||
|
||||
@@ -1187,6 +1187,26 @@ def check_and_delete_children(parent, data):
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
|
||||
def check_permissions(doc, perm_type='create'):
|
||||
try:
|
||||
doc.check_permission(perm_type)
|
||||
except:
|
||||
action = "add" if perm_type == 'create' else "update"
|
||||
frappe.throw(_("You do not have permissions to {} items in a Sales Order.").format(action), title=_("Insufficient Permissions"))
|
||||
|
||||
def get_new_child_item():
|
||||
if parent_doctype == "Sales Order":
|
||||
return set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
||||
if parent_doctype == "Purchase Order":
|
||||
return set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
||||
|
||||
def validate_quantity(child_item, d):
|
||||
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
||||
frappe.throw(_("Cannot set quantity less than delivered quantity"))
|
||||
|
||||
if parent_doctype == "Purchase Order" and flt(d.get("qty")) < flt(child_item.received_qty):
|
||||
frappe.throw(_("Cannot set quantity less than received quantity"))
|
||||
|
||||
data = json.loads(trans_items)
|
||||
|
||||
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
|
||||
@@ -1198,20 +1218,29 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
||||
new_child_flag = False
|
||||
if not d.get("docname"):
|
||||
new_child_flag = True
|
||||
if parent_doctype == "Sales Order":
|
||||
child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
||||
if parent_doctype == "Purchase Order":
|
||||
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
||||
check_permissions(parent, 'create')
|
||||
child_item = get_new_child_item()
|
||||
else:
|
||||
check_permissions(parent, 'write')
|
||||
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
||||
if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")):
|
||||
|
||||
prev_rate, new_rate = flt(child_item.get("rate")), flt(d.get("rate"))
|
||||
prev_qty, new_qty = flt(child_item.get("qty")), flt(d.get("qty"))
|
||||
prev_con_fac, new_con_fac = flt(child_item.get("conversion_factor")), flt(d.get("conversion_factor"))
|
||||
|
||||
if parent_doctype == 'Sales Order':
|
||||
prev_date, new_date = child_item.get("delivery_date"), d.get("delivery_date")
|
||||
elif parent_doctype == 'Purchase Order':
|
||||
prev_date, new_date = child_item.get("schedule_date"), d.get("schedule_date")
|
||||
|
||||
rate_unchanged = prev_rate == new_rate
|
||||
qty_unchanged = prev_qty == new_qty
|
||||
conversion_factor_unchanged = prev_con_fac == new_con_fac
|
||||
date_unchanged = prev_date == new_date if prev_date and new_date else False # in case of delivery note etc
|
||||
if rate_unchanged and qty_unchanged and conversion_factor_unchanged and date_unchanged:
|
||||
continue
|
||||
|
||||
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
||||
frappe.throw(_("Cannot set quantity less than delivered quantity"))
|
||||
|
||||
if parent_doctype == "Purchase Order" and flt(d.get("qty")) < flt(child_item.received_qty):
|
||||
frappe.throw(_("Cannot set quantity less than received quantity"))
|
||||
validate_quantity(child_item, d)
|
||||
|
||||
child_item.qty = flt(d.get("qty"))
|
||||
precision = child_item.precision("rate") or 2
|
||||
@@ -1222,6 +1251,18 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
||||
else:
|
||||
child_item.rate = flt(d.get("rate"))
|
||||
|
||||
if d.get("conversion_factor"):
|
||||
if child_item.stock_uom == child_item.uom:
|
||||
child_item.conversion_factor = 1
|
||||
else:
|
||||
child_item.conversion_factor = flt(d.get('conversion_factor'))
|
||||
|
||||
if d.get("delivery_date") and parent_doctype == 'Sales Order':
|
||||
child_item.delivery_date = d.get('delivery_date')
|
||||
|
||||
if d.get("schedule_date") and parent_doctype == 'Purchase Order':
|
||||
child_item.schedule_date = d.get('schedule_date')
|
||||
|
||||
if flt(child_item.price_list_rate):
|
||||
if flt(child_item.rate) > flt(child_item.price_list_rate):
|
||||
# if rate is greater than price_list_rate, set margin
|
||||
|
||||
@@ -340,7 +340,7 @@ class BuyingController(StockController):
|
||||
})
|
||||
|
||||
if not rm.rate:
|
||||
rm.rate = get_valuation_rate(raw_material_data.item_code, self.supplier_warehouse,
|
||||
rm.rate = get_valuation_rate(raw_material_data.rm_item_code, self.supplier_warehouse,
|
||||
self.doctype, self.name, currency=self.company_currency, company=self.company)
|
||||
|
||||
rm.amount = qty * flt(rm.rate)
|
||||
|
||||
@@ -70,7 +70,7 @@ def validate_item_variant_attributes(item, args=None):
|
||||
|
||||
else:
|
||||
attributes_list = attribute_values.get(attribute.lower(), [])
|
||||
validate_item_attribute_value(attributes_list, attribute, value, item.name)
|
||||
validate_item_attribute_value(attributes_list, attribute, value, item.name, from_variant=True)
|
||||
|
||||
def validate_is_incremental(numeric_attribute, attribute, value, item):
|
||||
from_range = numeric_attribute.from_range
|
||||
@@ -93,13 +93,20 @@ def validate_is_incremental(numeric_attribute, attribute, value, item):
|
||||
.format(attribute, from_range, to_range, increment, item),
|
||||
InvalidItemAttributeValueError, title=_('Invalid Attribute'))
|
||||
|
||||
def validate_item_attribute_value(attributes_list, attribute, attribute_value, item):
|
||||
def validate_item_attribute_value(attributes_list, attribute, attribute_value, item, from_variant=True):
|
||||
allow_rename_attribute_value = frappe.db.get_single_value('Item Variant Settings', 'allow_rename_attribute_value')
|
||||
if allow_rename_attribute_value:
|
||||
pass
|
||||
elif attribute_value not in attributes_list:
|
||||
frappe.throw(_("The value {0} is already assigned to an exisiting Item {2}.").format(
|
||||
attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Rename Not Allowed'))
|
||||
if from_variant:
|
||||
frappe.throw(_("{0} is not a valid Value for Attribute {1} of Item {2}.").format(
|
||||
frappe.bold(attribute_value), frappe.bold(attribute), frappe.bold(item)), InvalidItemAttributeValueError, title=_("Invalid Value"))
|
||||
else:
|
||||
msg = _("The value {0} is already assigned to an exisiting Item {1}.").format(
|
||||
frappe.bold(attribute_value), frappe.bold(item))
|
||||
msg += "<br>" + _("To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings.").format(frappe.bold("Allow Rename Attribute Value"))
|
||||
|
||||
frappe.throw(msg, InvalidItemAttributeValueError, title=_('Edit Not Allowed'))
|
||||
|
||||
def get_attribute_values(item):
|
||||
if not frappe.flags.attribute_values:
|
||||
|
||||
@@ -19,7 +19,8 @@ class QualityInspectionNotSubmittedError(frappe.ValidationError): pass
|
||||
class StockController(AccountsController):
|
||||
def validate(self):
|
||||
super(StockController, self).validate()
|
||||
self.validate_inspection()
|
||||
if not self.get('is_return'):
|
||||
self.validate_inspection()
|
||||
self.validate_serialized_batch()
|
||||
self.validate_customer_provided_item()
|
||||
|
||||
@@ -224,7 +225,9 @@ class StockController(AccountsController):
|
||||
|
||||
def check_expense_account(self, item):
|
||||
if not item.get("expense_account"):
|
||||
frappe.throw(_("Expense Account not set for Item {0}. Please set an Expense Account for the item in the Items table").format(item.item_code))
|
||||
frappe.throw(_("Row #{0}: Expense Account not set for Item {1}. Please set an Expense \
|
||||
Account in the Items table").format(item.idx, frappe.bold(item.item_code)),
|
||||
title=_("Expense Account Missing"))
|
||||
|
||||
else:
|
||||
is_expense_account = frappe.db.get_value("Account",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2015-09-07 14:37:01.886859",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@@ -16,26 +17,33 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Course",
|
||||
"options": "Course",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
{
|
||||
"fetch_from": "course.course_name",
|
||||
"fieldname": "course_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Course Name",
|
||||
"fetch_from": "course.course_name",
|
||||
"read_only":1
|
||||
"read_only": 1,
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "required",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory"
|
||||
"label": "Mandatory",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-06-12 12:42:12.845972",
|
||||
"links": [],
|
||||
"modified": "2020-06-09 18:56:10.213241",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Education",
|
||||
"name": "Program Course",
|
||||
@@ -45,4 +53,4 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
@@ -241,14 +241,17 @@ def get_order_taxes(shopify_order, shopify_settings):
|
||||
return taxes
|
||||
|
||||
def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
|
||||
"""Shipping lines represents the shipping details,
|
||||
each such shipping detail consists of a list of tax_lines"""
|
||||
for shipping_charge in shipping_lines:
|
||||
taxes.append({
|
||||
"charge_type": _("Actual"),
|
||||
"account_head": get_tax_account_head(shipping_charge),
|
||||
"description": shipping_charge["title"],
|
||||
"tax_amount": shipping_charge["price"],
|
||||
"cost_center": shopify_settings.cost_center
|
||||
})
|
||||
for tax in shipping_charge.get("tax_lines"):
|
||||
taxes.append({
|
||||
"charge_type": _("Actual"),
|
||||
"account_head": get_tax_account_head(tax),
|
||||
"description": tax["title"],
|
||||
"tax_amount": tax["price"],
|
||||
"cost_center": shopify_settings.cost_center
|
||||
})
|
||||
|
||||
return taxes
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Tally Migration', {
|
||||
frappe.provide("erpnext.tally_migration");
|
||||
|
||||
frappe.ui.form.on("Tally Migration", {
|
||||
onload: function (frm) {
|
||||
let reload_status = true;
|
||||
frappe.realtime.on("tally_migration_progress_update", function (data) {
|
||||
@@ -35,7 +37,17 @@ frappe.ui.form.on('Tally Migration', {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function (frm) {
|
||||
frm.trigger("show_logs_preview");
|
||||
erpnext.tally_migration.failed_import_log = JSON.parse(frm.doc.failed_import_log);
|
||||
erpnext.tally_migration.fixed_errors_log = JSON.parse(frm.doc.fixed_errors_log);
|
||||
|
||||
["default_round_off_account", "default_warehouse", "default_cost_center"].forEach(account => {
|
||||
frm.toggle_reqd(account, frm.doc.is_master_data_imported === 1)
|
||||
frm.toggle_enable(account, frm.doc.is_day_book_data_processed != 1)
|
||||
})
|
||||
|
||||
if (frm.doc.master_data && !frm.doc.is_master_data_imported) {
|
||||
if (frm.doc.is_master_data_processed) {
|
||||
if (frm.doc.status != "Importing Master Data") {
|
||||
@@ -47,6 +59,7 @@ frappe.ui.form.on('Tally Migration', {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frm.doc.day_book_data && !frm.doc.is_day_book_data_imported) {
|
||||
if (frm.doc.is_day_book_data_processed) {
|
||||
if (frm.doc.status != "Importing Day Book Data") {
|
||||
@@ -59,6 +72,17 @@ frappe.ui.form.on('Tally Migration', {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
erpnext_company: function (frm) {
|
||||
frappe.db.exists("Company", frm.doc.erpnext_company).then(exists => {
|
||||
if (exists) {
|
||||
frappe.msgprint(
|
||||
__("Company {0} already exists. Continuing will overwrite the Company and Chart of Accounts", [frm.doc.erpnext_company]),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
add_button: function (frm, label, method) {
|
||||
frm.add_custom_button(
|
||||
label,
|
||||
@@ -71,5 +95,255 @@ frappe.ui.form.on('Tally Migration', {
|
||||
frm.reload_doc();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
render_html_table(frm, shown_logs, hidden_logs, field) {
|
||||
if (shown_logs && shown_logs.length > 0) {
|
||||
frm.toggle_display(field, true);
|
||||
} else {
|
||||
frm.toggle_display(field, false);
|
||||
return
|
||||
}
|
||||
let rows = erpnext.tally_migration.get_html_rows(shown_logs, field);
|
||||
let rows_head, table_caption;
|
||||
|
||||
let table_footer = (hidden_logs && (hidden_logs.length > 0)) ? `<tr class="text-muted">
|
||||
<td colspan="4">And ${hidden_logs.length} more others</td>
|
||||
</tr>`: "";
|
||||
|
||||
if (field === "fixed_error_log_preview") {
|
||||
rows_head = `<th width="75%">${__("Meta Data")}</th>
|
||||
<th width="10%">${__("Unresolve")}</th>`
|
||||
table_caption = "Resolved Issues"
|
||||
} else {
|
||||
rows_head = `<th width="75%">${__("Error Message")}</th>
|
||||
<th width="10%">${__("Create")}</th>`
|
||||
table_caption = "Error Log"
|
||||
}
|
||||
|
||||
frm.get_field(field).$wrapper.html(`
|
||||
<table class="table table-bordered">
|
||||
<caption>${table_caption}</caption>
|
||||
<tr class="text-muted">
|
||||
<th width="5%">${__("#")}</th>
|
||||
<th width="10%">${__("DocType")}</th>
|
||||
${rows_head}
|
||||
</tr>
|
||||
${rows}
|
||||
${table_footer}
|
||||
</table>
|
||||
`);
|
||||
},
|
||||
|
||||
show_error_summary(frm) {
|
||||
let summary = erpnext.tally_migration.failed_import_log.reduce((summary, row) => {
|
||||
if (row.doc) {
|
||||
if (summary[row.doc.doctype]) {
|
||||
summary[row.doc.doctype] += 1;
|
||||
} else {
|
||||
summary[row.doc.doctype] = 1;
|
||||
}
|
||||
}
|
||||
return summary
|
||||
}, {});
|
||||
console.table(summary);
|
||||
},
|
||||
|
||||
show_logs_preview(frm) {
|
||||
let empty = "[]";
|
||||
let import_log = frm.doc.failed_import_log || empty;
|
||||
let completed_log = frm.doc.fixed_errors_log || empty;
|
||||
let render_section = !(import_log === completed_log && import_log === empty);
|
||||
|
||||
frm.toggle_display("import_log_section", render_section);
|
||||
if (render_section) {
|
||||
frm.trigger("show_error_summary");
|
||||
frm.trigger("show_errored_import_log");
|
||||
frm.trigger("show_fixed_errors_log");
|
||||
}
|
||||
},
|
||||
|
||||
show_errored_import_log(frm) {
|
||||
let import_log = erpnext.tally_migration.failed_import_log;
|
||||
let logs = import_log.slice(0, 20);
|
||||
let hidden_logs = import_log.slice(20);
|
||||
|
||||
frm.events.render_html_table(frm, logs, hidden_logs, "failed_import_preview");
|
||||
},
|
||||
|
||||
show_fixed_errors_log(frm) {
|
||||
let completed_log = erpnext.tally_migration.fixed_errors_log;
|
||||
let logs = completed_log.slice(0, 20);
|
||||
let hidden_logs = completed_log.slice(20);
|
||||
|
||||
frm.events.render_html_table(frm, logs, hidden_logs, "fixed_error_log_preview");
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.tally_migration.getError = (traceback) => {
|
||||
/* Extracts the Error Message from the Python Traceback or Solved error */
|
||||
let is_multiline = traceback.trim().indexOf("\n") != -1;
|
||||
let message;
|
||||
|
||||
if (is_multiline) {
|
||||
let exc_error_idx = traceback.trim().lastIndexOf("\n") + 1
|
||||
let error_line = traceback.substr(exc_error_idx)
|
||||
let split_str_idx = (error_line.indexOf(':') > 0) ? error_line.indexOf(':') + 1 : 0;
|
||||
message = error_line.slice(split_str_idx).trim();
|
||||
} else {
|
||||
message = traceback;
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
erpnext.tally_migration.cleanDoc = (obj) => {
|
||||
/* Strips all null and empty values of your JSON object */
|
||||
let temp = obj;
|
||||
$.each(temp, function(key, value){
|
||||
if (value === "" || value === null){
|
||||
delete obj[key];
|
||||
} else if (Object.prototype.toString.call(value) === '[object Object]') {
|
||||
erpnext.tally_migration.cleanDoc(value);
|
||||
} else if ($.isArray(value)) {
|
||||
$.each(value, function (k,v) { erpnext.tally_migration.cleanDoc(v); });
|
||||
}
|
||||
});
|
||||
return temp;
|
||||
}
|
||||
|
||||
erpnext.tally_migration.unresolve = (document) => {
|
||||
/* Mark document migration as unresolved ie. move to failed error log */
|
||||
let frm = cur_frm;
|
||||
let failed_log = erpnext.tally_migration.failed_import_log;
|
||||
let fixed_log = erpnext.tally_migration.fixed_errors_log;
|
||||
|
||||
let modified_fixed_log = fixed_log.filter(row => {
|
||||
if (!frappe.utils.deep_equal(erpnext.tally_migration.cleanDoc(row.doc), document)) {
|
||||
return row
|
||||
}
|
||||
});
|
||||
|
||||
failed_log.push({ doc: document, exc: `Marked unresolved on ${Date()}` });
|
||||
|
||||
frm.doc.failed_import_log = JSON.stringify(failed_log);
|
||||
frm.doc.fixed_errors_log = JSON.stringify(modified_fixed_log);
|
||||
|
||||
frm.dirty();
|
||||
frm.save();
|
||||
}
|
||||
|
||||
erpnext.tally_migration.resolve = (document) => {
|
||||
/* Mark document migration as resolved ie. move to fixed error log */
|
||||
let frm = cur_frm;
|
||||
let failed_log = erpnext.tally_migration.failed_import_log;
|
||||
let fixed_log = erpnext.tally_migration.fixed_errors_log;
|
||||
|
||||
let modified_failed_log = failed_log.filter(row => {
|
||||
if (!frappe.utils.deep_equal(erpnext.tally_migration.cleanDoc(row.doc), document)) {
|
||||
return row
|
||||
}
|
||||
});
|
||||
fixed_log.push({ doc: document, exc: `Solved on ${Date()}` });
|
||||
|
||||
frm.doc.failed_import_log = JSON.stringify(modified_failed_log);
|
||||
frm.doc.fixed_errors_log = JSON.stringify(fixed_log);
|
||||
|
||||
frm.dirty();
|
||||
frm.save();
|
||||
}
|
||||
|
||||
erpnext.tally_migration.create_new_doc = (document) => {
|
||||
/* Mark as resolved and create new document */
|
||||
erpnext.tally_migration.resolve(document);
|
||||
return frappe.call({
|
||||
type: "POST",
|
||||
method: 'erpnext.erpnext_integrations.doctype.tally_migration.tally_migration.new_doc',
|
||||
args: {
|
||||
document
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
frappe.model.sync(r.message);
|
||||
frappe.get_doc(r.message.doctype, r.message.name).__run_link_triggers = true;
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
erpnext.tally_migration.get_html_rows = (logs, field) => {
|
||||
let index = 0;
|
||||
let rows = logs
|
||||
.map(({ doc, exc }) => {
|
||||
let id = frappe.dom.get_unique_id();
|
||||
let traceback = exc;
|
||||
|
||||
let error_message = erpnext.tally_migration.getError(traceback);
|
||||
index++;
|
||||
|
||||
let show_traceback = `
|
||||
<button class="btn btn-default btn-xs m-3" type="button" data-toggle="collapse" data-target="#${id}-traceback" aria-expanded="false" aria-controls="${id}-traceback">
|
||||
${__("Show Traceback")}
|
||||
</button>
|
||||
<div class="collapse margin-top" id="${id}-traceback">
|
||||
<div class="well">
|
||||
<pre style="font-size: smaller;">${traceback}</pre>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
let show_doc = `
|
||||
<button class='btn btn-default btn-xs m-3' type='button' data-toggle='collapse' data-target='#${id}-doc' aria-expanded='false' aria-controls='${id}-doc'>
|
||||
${__("Show Document")}
|
||||
</button>
|
||||
<div class="collapse margin-top" id="${id}-doc">
|
||||
<div class="well">
|
||||
<pre style="font-size: smaller;">${JSON.stringify(erpnext.tally_migration.cleanDoc(doc), null, 1)}</pre>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
let create_button = `
|
||||
<button class='btn btn-default btn-xs m-3' type='button' onclick='erpnext.tally_migration.create_new_doc(${JSON.stringify(doc)})'>
|
||||
${__("Create Document")}
|
||||
</button>`
|
||||
|
||||
let mark_as_unresolved = `
|
||||
<button class='btn btn-default btn-xs m-3' type='button' onclick='erpnext.tally_migration.unresolve(${JSON.stringify(doc)})'>
|
||||
${__("Mark as unresolved")}
|
||||
</button>`
|
||||
|
||||
if (field === "fixed_error_log_preview") {
|
||||
return `<tr>
|
||||
<td>${index}</td>
|
||||
<td>
|
||||
<div>${doc.doctype}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>${error_message}</div>
|
||||
<div>${show_doc}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>${mark_as_unresolved}</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
} else {
|
||||
return `<tr>
|
||||
<td>${index}</td>
|
||||
<td>
|
||||
<div>${doc.doctype}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>${error_message}</div>
|
||||
<div>${show_traceback}</div>
|
||||
<div>${show_doc}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>${create_button}</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
}).join("");
|
||||
|
||||
return rows
|
||||
}
|
||||
@@ -28,14 +28,19 @@
|
||||
"vouchers",
|
||||
"accounts_section",
|
||||
"default_warehouse",
|
||||
"round_off_account",
|
||||
"default_round_off_account",
|
||||
"column_break_21",
|
||||
"default_cost_center",
|
||||
"day_book_section",
|
||||
"day_book_data",
|
||||
"column_break_27",
|
||||
"is_day_book_data_processed",
|
||||
"is_day_book_data_imported"
|
||||
"is_day_book_data_imported",
|
||||
"import_log_section",
|
||||
"failed_import_log",
|
||||
"fixed_errors_log",
|
||||
"failed_import_preview",
|
||||
"fixed_error_log_preview"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -57,6 +62,7 @@
|
||||
"fieldname": "tally_creditors_account",
|
||||
"fieldtype": "Data",
|
||||
"label": "Tally Creditors Account",
|
||||
"read_only_depends_on": "eval:doc.is_master_data_processed==1",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -69,6 +75,7 @@
|
||||
"fieldname": "tally_debtors_account",
|
||||
"fieldtype": "Data",
|
||||
"label": "Tally Debtors Account",
|
||||
"read_only_depends_on": "eval:doc.is_master_data_processed==1",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -92,7 +99,7 @@
|
||||
"fieldname": "erpnext_company",
|
||||
"fieldtype": "Data",
|
||||
"label": "ERPNext Company",
|
||||
"read_only_depends_on": "eval:doc.is_master_data_processed == 1"
|
||||
"read_only_depends_on": "eval:doc.is_master_data_processed==1"
|
||||
},
|
||||
{
|
||||
"fieldname": "processed_files_section",
|
||||
@@ -136,6 +143,7 @@
|
||||
},
|
||||
{
|
||||
"depends_on": "is_master_data_imported",
|
||||
"description": "The accounts are set by the system automatically but do confirm these defaults",
|
||||
"fieldname": "accounts_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Accounts"
|
||||
@@ -146,12 +154,6 @@
|
||||
"label": "Default Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"fieldname": "round_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Round Off Account",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_21",
|
||||
"fieldtype": "Column Break"
|
||||
@@ -212,11 +214,47 @@
|
||||
"fieldname": "default_uom",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default UOM",
|
||||
"options": "UOM"
|
||||
"options": "UOM",
|
||||
"read_only_depends_on": "eval:doc.is_master_data_imported==1"
|
||||
},
|
||||
{
|
||||
"default": "[]",
|
||||
"fieldname": "failed_import_log",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"options": "JSON"
|
||||
},
|
||||
{
|
||||
"fieldname": "failed_import_preview",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Failed Import Log"
|
||||
},
|
||||
{
|
||||
"fieldname": "import_log_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Import Log"
|
||||
},
|
||||
{
|
||||
"fieldname": "default_round_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Round Off Account",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"default": "[]",
|
||||
"fieldname": "fixed_errors_log",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"options": "JSON"
|
||||
},
|
||||
{
|
||||
"fieldname": "fixed_error_log_preview",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Fixed Error Log"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-04-16 13:03:28.894919",
|
||||
"modified": "2020-04-28 00:29:18.039826",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "Tally Migration",
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import zipfile
|
||||
from decimal import Decimal
|
||||
@@ -15,18 +16,34 @@ from bs4 import BeautifulSoup as bs
|
||||
import frappe
|
||||
from erpnext import encode_company_abbr
|
||||
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
|
||||
from erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer import unset_existing_data
|
||||
|
||||
from frappe import _
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.naming import getseries, revert_series_if_last
|
||||
from frappe.utils.data import format_datetime
|
||||
|
||||
|
||||
PRIMARY_ACCOUNT = "Primary"
|
||||
VOUCHER_CHUNK_SIZE = 500
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def new_doc(document):
|
||||
document = json.loads(document)
|
||||
doctype = document.pop("doctype")
|
||||
document.pop("name", None)
|
||||
doc = frappe.new_doc(doctype)
|
||||
doc.update(document)
|
||||
|
||||
return doc
|
||||
|
||||
class TallyMigration(Document):
|
||||
def validate(self):
|
||||
failed_import_log = json.loads(self.failed_import_log)
|
||||
sorted_failed_import_log = sorted(failed_import_log, key=lambda row: row["doc"]["creation"])
|
||||
self.failed_import_log = json.dumps(sorted_failed_import_log)
|
||||
|
||||
def autoname(self):
|
||||
if not self.name:
|
||||
self.name = "Tally Migration on " + format_datetime(self.creation)
|
||||
@@ -65,9 +82,17 @@ class TallyMigration(Document):
|
||||
"attached_to_name": self.name,
|
||||
"content": json.dumps(value),
|
||||
"is_private": True
|
||||
}).insert()
|
||||
})
|
||||
try:
|
||||
f.insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
setattr(self, key, f.file_url)
|
||||
|
||||
def set_account_defaults(self):
|
||||
self.default_cost_center, self.default_round_off_account = frappe.db.get_value("Company", self.erpnext_company, ["cost_center", "round_off_account"])
|
||||
self.default_warehouse = frappe.db.get_value("Stock Settings", "Stock Settings", "default_warehouse")
|
||||
|
||||
def _process_master_data(self):
|
||||
def get_company_name(collection):
|
||||
return collection.find_all("REMOTECMPINFO.LIST")[0].REMOTECMPNAME.string.strip()
|
||||
@@ -84,7 +109,11 @@ class TallyMigration(Document):
|
||||
children, parents = get_children_and_parent_dict(accounts)
|
||||
group_set = [acc[1] for acc in accounts if acc[2]]
|
||||
children, customers, suppliers = remove_parties(parents, children, group_set)
|
||||
coa = traverse({}, children, roots, roots, group_set)
|
||||
|
||||
try:
|
||||
coa = traverse({}, children, roots, roots, group_set)
|
||||
except RecursionError:
|
||||
self.log(_("Error occured while parsing Chart of Accounts: Please make sure that no two accounts have the same name"))
|
||||
|
||||
for account in coa:
|
||||
coa[account]["root_type"] = root_type_map[account]
|
||||
@@ -126,14 +155,18 @@ class TallyMigration(Document):
|
||||
def remove_parties(parents, children, group_set):
|
||||
customers, suppliers = set(), set()
|
||||
for account in parents:
|
||||
found = False
|
||||
if self.tally_creditors_account in parents[account]:
|
||||
children.pop(account, None)
|
||||
found = True
|
||||
if account not in group_set:
|
||||
suppliers.add(account)
|
||||
elif self.tally_debtors_account in parents[account]:
|
||||
children.pop(account, None)
|
||||
if self.tally_debtors_account in parents[account]:
|
||||
found = True
|
||||
if account not in group_set:
|
||||
customers.add(account)
|
||||
if found:
|
||||
children.pop(account, None)
|
||||
|
||||
return children, customers, suppliers
|
||||
|
||||
def traverse(tree, children, accounts, roots, group_set):
|
||||
@@ -151,6 +184,7 @@ class TallyMigration(Document):
|
||||
parties, addresses = [], []
|
||||
for account in collection.find_all("LEDGER"):
|
||||
party_type = None
|
||||
links = []
|
||||
if account.NAME.string.strip() in customers:
|
||||
party_type = "Customer"
|
||||
parties.append({
|
||||
@@ -161,7 +195,9 @@ class TallyMigration(Document):
|
||||
"territory": "All Territories",
|
||||
"customer_type": "Individual",
|
||||
})
|
||||
elif account.NAME.string.strip() in suppliers:
|
||||
links.append({"link_doctype": party_type, "link_name": account["NAME"]})
|
||||
|
||||
if account.NAME.string.strip() in suppliers:
|
||||
party_type = "Supplier"
|
||||
parties.append({
|
||||
"doctype": party_type,
|
||||
@@ -170,6 +206,8 @@ class TallyMigration(Document):
|
||||
"supplier_group": "All Supplier Groups",
|
||||
"supplier_type": "Individual",
|
||||
})
|
||||
links.append({"link_doctype": party_type, "link_name": account["NAME"]})
|
||||
|
||||
if party_type:
|
||||
address = "\n".join([a.string.strip() for a in account.find_all("ADDRESS")])
|
||||
addresses.append({
|
||||
@@ -183,7 +221,7 @@ class TallyMigration(Document):
|
||||
"mobile": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
|
||||
"phone": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
|
||||
"gstin": account.PARTYGSTIN.string.strip() if account.PARTYGSTIN else None,
|
||||
"links": [{"link_doctype": party_type, "link_name": account["NAME"]}],
|
||||
"links": links
|
||||
})
|
||||
return parties, addresses
|
||||
|
||||
@@ -242,12 +280,18 @@ class TallyMigration(Document):
|
||||
def create_company_and_coa(coa_file_url):
|
||||
coa_file = frappe.get_doc("File", {"file_url": coa_file_url})
|
||||
frappe.local.flags.ignore_chart_of_accounts = True
|
||||
company = frappe.get_doc({
|
||||
"doctype": "Company",
|
||||
"company_name": self.erpnext_company,
|
||||
"default_currency": "INR",
|
||||
"enable_perpetual_inventory": 0,
|
||||
}).insert()
|
||||
|
||||
try:
|
||||
company = frappe.get_doc({
|
||||
"doctype": "Company",
|
||||
"company_name": self.erpnext_company,
|
||||
"default_currency": "INR",
|
||||
"enable_perpetual_inventory": 0,
|
||||
}).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
company = frappe.get_doc("Company", self.erpnext_company)
|
||||
unset_existing_data(self.erpnext_company)
|
||||
|
||||
frappe.local.flags.ignore_chart_of_accounts = False
|
||||
create_charts(company.name, custom_chart=json.loads(coa_file.get_content()))
|
||||
company.create_default_warehouses()
|
||||
@@ -256,36 +300,35 @@ class TallyMigration(Document):
|
||||
parties_file = frappe.get_doc("File", {"file_url": parties_file_url})
|
||||
for party in json.loads(parties_file.get_content()):
|
||||
try:
|
||||
frappe.get_doc(party).insert()
|
||||
party_doc = frappe.get_doc(party)
|
||||
party_doc.insert()
|
||||
except:
|
||||
self.log(party)
|
||||
self.log(party_doc)
|
||||
addresses_file = frappe.get_doc("File", {"file_url": addresses_file_url})
|
||||
for address in json.loads(addresses_file.get_content()):
|
||||
try:
|
||||
frappe.get_doc(address).insert(ignore_mandatory=True)
|
||||
address_doc = frappe.get_doc(address)
|
||||
address_doc.insert(ignore_mandatory=True)
|
||||
except:
|
||||
try:
|
||||
gstin = address.pop("gstin", None)
|
||||
frappe.get_doc(address).insert(ignore_mandatory=True)
|
||||
self.log({"address": address, "message": "Invalid GSTIN: {}. Address was created without GSTIN".format(gstin)})
|
||||
except:
|
||||
self.log(address)
|
||||
self.log(address_doc)
|
||||
|
||||
def create_items_uoms(items_file_url, uoms_file_url):
|
||||
uoms_file = frappe.get_doc("File", {"file_url": uoms_file_url})
|
||||
for uom in json.loads(uoms_file.get_content()):
|
||||
if not frappe.db.exists(uom):
|
||||
try:
|
||||
frappe.get_doc(uom).insert()
|
||||
uom_doc = frappe.get_doc(uom)
|
||||
uom_doc.insert()
|
||||
except:
|
||||
self.log(uom)
|
||||
self.log(uom_doc)
|
||||
|
||||
items_file = frappe.get_doc("File", {"file_url": items_file_url})
|
||||
for item in json.loads(items_file.get_content()):
|
||||
try:
|
||||
frappe.get_doc(item).insert()
|
||||
item_doc = frappe.get_doc(item)
|
||||
item_doc.insert()
|
||||
except:
|
||||
self.log(item)
|
||||
self.log(item_doc)
|
||||
|
||||
try:
|
||||
self.publish("Import Master Data", _("Creating Company and Importing Chart of Accounts"), 1, 4)
|
||||
@@ -299,10 +342,13 @@ class TallyMigration(Document):
|
||||
|
||||
self.publish("Import Master Data", _("Done"), 4, 4)
|
||||
|
||||
self.set_account_defaults()
|
||||
self.is_master_data_imported = 1
|
||||
frappe.db.commit()
|
||||
|
||||
except:
|
||||
self.publish("Import Master Data", _("Process Failed"), -1, 5)
|
||||
frappe.db.rollback()
|
||||
self.log()
|
||||
|
||||
finally:
|
||||
@@ -323,7 +369,9 @@ class TallyMigration(Document):
|
||||
processed_voucher = function(voucher)
|
||||
if processed_voucher:
|
||||
vouchers.append(processed_voucher)
|
||||
frappe.db.commit()
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
self.log(voucher)
|
||||
return vouchers
|
||||
|
||||
@@ -349,6 +397,7 @@ class TallyMigration(Document):
|
||||
journal_entry = {
|
||||
"doctype": "Journal Entry",
|
||||
"tally_guid": voucher.GUID.string.strip(),
|
||||
"tally_voucher_no": voucher.VOUCHERNUMBER.string.strip() if voucher.VOUCHERNUMBER else "",
|
||||
"posting_date": voucher.DATE.string.strip(),
|
||||
"company": self.erpnext_company,
|
||||
"accounts": accounts,
|
||||
@@ -377,6 +426,7 @@ class TallyMigration(Document):
|
||||
"doctype": doctype,
|
||||
party_field: voucher.PARTYNAME.string.strip(),
|
||||
"tally_guid": voucher.GUID.string.strip(),
|
||||
"tally_voucher_no": voucher.VOUCHERNUMBER.string.strip() if voucher.VOUCHERNUMBER else "",
|
||||
"posting_date": voucher.DATE.string.strip(),
|
||||
"due_date": voucher.DATE.string.strip(),
|
||||
"items": get_voucher_items(voucher, doctype),
|
||||
@@ -468,14 +518,21 @@ class TallyMigration(Document):
|
||||
oldest_year = new_year
|
||||
|
||||
def create_custom_fields(doctypes):
|
||||
for doctype in doctypes:
|
||||
df = {
|
||||
"fieldtype": "Data",
|
||||
"fieldname": "tally_guid",
|
||||
"read_only": 1,
|
||||
"label": "Tally GUID"
|
||||
}
|
||||
create_custom_field(doctype, df)
|
||||
tally_guid_df = {
|
||||
"fieldtype": "Data",
|
||||
"fieldname": "tally_guid",
|
||||
"read_only": 1,
|
||||
"label": "Tally GUID"
|
||||
}
|
||||
tally_voucher_no_df = {
|
||||
"fieldtype": "Data",
|
||||
"fieldname": "tally_voucher_no",
|
||||
"read_only": 1,
|
||||
"label": "Tally Voucher Number"
|
||||
}
|
||||
for df in [tally_guid_df, tally_voucher_no_df]:
|
||||
for doctype in doctypes:
|
||||
create_custom_field(doctype, df)
|
||||
|
||||
def create_price_list():
|
||||
frappe.get_doc({
|
||||
@@ -490,7 +547,7 @@ class TallyMigration(Document):
|
||||
try:
|
||||
frappe.db.set_value("Account", encode_company_abbr(self.tally_creditors_account, self.erpnext_company), "account_type", "Payable")
|
||||
frappe.db.set_value("Account", encode_company_abbr(self.tally_debtors_account, self.erpnext_company), "account_type", "Receivable")
|
||||
frappe.db.set_value("Company", self.erpnext_company, "round_off_account", self.round_off_account)
|
||||
frappe.db.set_value("Company", self.erpnext_company, "round_off_account", self.default_round_off_account)
|
||||
|
||||
vouchers_file = frappe.get_doc("File", {"file_url": self.vouchers})
|
||||
vouchers = json.loads(vouchers_file.get_content())
|
||||
@@ -521,11 +578,14 @@ class TallyMigration(Document):
|
||||
|
||||
for index, voucher in enumerate(chunk, start=start):
|
||||
try:
|
||||
doc = frappe.get_doc(voucher).insert()
|
||||
doc.submit()
|
||||
voucher_doc = frappe.get_doc(voucher)
|
||||
voucher_doc.insert()
|
||||
voucher_doc.submit()
|
||||
self.publish("Importing Vouchers", _("{} of {}").format(index, total), index, total)
|
||||
frappe.db.commit()
|
||||
except:
|
||||
self.log(voucher)
|
||||
frappe.db.rollback()
|
||||
self.log(voucher_doc)
|
||||
|
||||
if is_last:
|
||||
self.status = ""
|
||||
@@ -551,9 +611,22 @@ class TallyMigration(Document):
|
||||
frappe.enqueue_doc(self.doctype, self.name, "_import_day_book_data", queue="long", timeout=3600)
|
||||
|
||||
def log(self, data=None):
|
||||
data = data or self.status
|
||||
message = "\n".join(["Data:", json.dumps(data, default=str, indent=4), "--" * 50, "\nException:", traceback.format_exc()])
|
||||
return frappe.log_error(title="Tally Migration Error", message=message)
|
||||
if isinstance(data, frappe.model.document.Document):
|
||||
if sys.exc_info()[1].__class__ != frappe.DuplicateEntryError:
|
||||
failed_import_log = json.loads(self.failed_import_log)
|
||||
doc = data.as_dict()
|
||||
failed_import_log.append({
|
||||
"doc": doc,
|
||||
"exc": traceback.format_exc()
|
||||
})
|
||||
self.failed_import_log = json.dumps(failed_import_log, separators=(',', ':'))
|
||||
self.save()
|
||||
frappe.db.commit()
|
||||
|
||||
else:
|
||||
data = data or self.status
|
||||
message = "\n".join(["Data:", json.dumps(data, default=str, indent=4), "--" * 50, "\nException:", traceback.format_exc()])
|
||||
return frappe.log_error(title="Tally Migration Error", message=message)
|
||||
|
||||
def set_status(self, status=""):
|
||||
self.status = status
|
||||
|
||||
@@ -113,13 +113,13 @@ frappe.ui.form.on('Employee Advance', {
|
||||
employee: function (frm) {
|
||||
if (frm.doc.employee) {
|
||||
return frappe.call({
|
||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_due_advance_amount",
|
||||
method: "erpnext.hr.doctype.employee_advance.employee_advance.get_pending_amount",
|
||||
args: {
|
||||
"employee": frm.doc.employee,
|
||||
"posting_date": frm.doc.posting_date
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.set_value("due_advance_amount",r.message);
|
||||
frm.set_value("pending_amount",r.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"column_break_11",
|
||||
"advance_amount",
|
||||
"paid_amount",
|
||||
"due_advance_amount",
|
||||
"pending_amount",
|
||||
"claimed_amount",
|
||||
"return_amount",
|
||||
"section_break_7",
|
||||
@@ -101,14 +101,6 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cur_frm.doc.employee",
|
||||
"fieldname": "due_advance_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Due Advance Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "claimed_amount",
|
||||
"fieldtype": "Currency",
|
||||
@@ -169,11 +161,25 @@
|
||||
"label": "Returned Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "repay_unclaimed_amount_from_salary",
|
||||
"fieldtype": "Check",
|
||||
"label": "Repay unclaimed amount from salary"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cur_frm.doc.employee",
|
||||
"fieldname": "pending_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Pending Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-15 19:04:07.044505",
|
||||
"modified": "2020-06-12 12:42:39.833818",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Advance",
|
||||
|
||||
@@ -95,7 +95,7 @@ class EmployeeAdvance(Document):
|
||||
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_due_advance_amount(employee, posting_date):
|
||||
def get_pending_amount(employee, posting_date):
|
||||
employee_due_amount = frappe.get_all("Employee Advance", \
|
||||
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
||||
fields = ["advance_amount", "paid_amount"])
|
||||
|
||||
@@ -154,6 +154,14 @@ frappe.ui.form.on("Expense Claim", {
|
||||
}
|
||||
};
|
||||
});
|
||||
frm.set_query("cost_center", "expenses", function() {
|
||||
return {
|
||||
filters: {
|
||||
"company": frm.doc.company,
|
||||
"is_group": 0
|
||||
}
|
||||
};
|
||||
});
|
||||
frm.set_query("account_head", "taxes", function(doc) {
|
||||
return {
|
||||
filters: [
|
||||
|
||||
@@ -101,8 +101,16 @@ class BOM(WebsiteGenerator):
|
||||
if self.routing:
|
||||
self.set("operations", [])
|
||||
for d in frappe.get_all("BOM Operation", fields = ["*"],
|
||||
filters = {'parenttype': 'Routing', 'parent': self.routing}):
|
||||
child = self.append('operations', d)
|
||||
filters = {'parenttype': 'Routing', 'parent': self.routing}, order_by="idx"):
|
||||
child = self.append('operations', {
|
||||
"operation": d.operation,
|
||||
"workstation": d.workstation,
|
||||
"description": d.description,
|
||||
"time_in_mins": d.time_in_mins,
|
||||
"batch_size": d.batch_size,
|
||||
"operating_cost": d.operating_cost,
|
||||
"idx": d.idx
|
||||
})
|
||||
child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)
|
||||
|
||||
def validate_rm_item(self, item):
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.doctype == 'BOM'",
|
||||
"fieldname": "base_hour_rate",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Base Hour Rate(Company Currency)",
|
||||
@@ -87,6 +88,7 @@
|
||||
},
|
||||
{
|
||||
"default": "5",
|
||||
"depends_on": "eval:parent.doctype == 'BOM'",
|
||||
"fieldname": "base_operating_cost",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Operating Cost(Company Currency)",
|
||||
@@ -108,12 +110,12 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-07-16 22:35:55.374037",
|
||||
"modified_by": "govindsmenokee@gmail.com",
|
||||
"modified": "2020-06-16 17:01:11.128420",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Operation",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,6 @@ frappe.ui.form.on('BOM Operation', {
|
||||
name: d.workstation
|
||||
},
|
||||
callback: function (data) {
|
||||
frappe.model.set_value(d.doctype, d.name, "base_hour_rate", data.message.hour_rate);
|
||||
frappe.model.set_value(d.doctype, d.name, "hour_rate", data.message.hour_rate);
|
||||
frm.events.calculate_operating_cost(frm, d);
|
||||
}
|
||||
|
||||
@@ -669,3 +669,5 @@ erpnext.patches.v12_0.set_serial_no_status #2020-05-21
|
||||
erpnext.patches.v12_0.update_price_list_currency_in_bom
|
||||
erpnext.patches.v12_0.update_uom_conversion_factor
|
||||
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
|
||||
execute:frappe.reload_doc("HR", "doctype", "Employee Advance")
|
||||
erpnext.patches.v12_0.move_due_advance_amount_to_pending_amount
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2019, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
''' Move from due_advance_amount to pending_amount '''
|
||||
|
||||
if frappe.db.has_column("Employee Advance", "due_advance_amount"):
|
||||
frappe.db.sql(''' UPDATE `tabEmployee Advance` SET pending_amount=due_advance_amount ''')
|
||||
@@ -1,5 +1,6 @@
|
||||
import frappe
|
||||
import numpy as np
|
||||
from frappe.utils import cint
|
||||
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
|
||||
|
||||
def get_field_filter_data():
|
||||
@@ -265,6 +266,8 @@ def get_next_attribute_and_values(item_code, selected_attributes):
|
||||
else:
|
||||
product_info = None
|
||||
|
||||
product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
|
||||
|
||||
return {
|
||||
'next_attribute': next_attribute,
|
||||
'valid_options_for_attributes': valid_options_for_attributes,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
setup: function() {
|
||||
this._super();
|
||||
frappe.flags.hide_serial_batch_dialog = true;
|
||||
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
var has_margin_field = frappe.meta.has_field(cdt, 'margin_type');
|
||||
@@ -539,7 +538,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
if (show_batch_dialog)
|
||||
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
||||
.then((r) => {
|
||||
if(r.message.has_batch_no || r.message.has_serial_no) {
|
||||
if(r.message && !frappe.flags.hide_serial_batch_dialog &&
|
||||
(r.message.has_batch_no || r.message.has_serial_no)) {
|
||||
frappe.flags.hide_serial_batch_dialog = false;
|
||||
}
|
||||
});
|
||||
@@ -879,7 +879,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
shipping_rule: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.shipping_rule && this.frm.doc.shipping_address) {
|
||||
if(this.frm.doc.shipping_rule) {
|
||||
return this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "apply_shipping_rule",
|
||||
|
||||
@@ -487,7 +487,14 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
fieldtype: 'Date',
|
||||
fieldname: frm.doc.doctype == 'Sales Order' ? "delivery_date" : "schedule_date",
|
||||
in_list_view: 1,
|
||||
label: frm.doc.doctype == 'Sales Order' ? __("Delivery Date") : __("Reqd by date")
|
||||
label: frm.doc.doctype == 'Sales Order' ? __("Delivery Date") : __("Reqd by date"),
|
||||
reqd: 1
|
||||
})
|
||||
fields.splice(3, 0, {
|
||||
fieldtype: 'Float',
|
||||
fieldname: "conversion_factor",
|
||||
in_list_view: 1,
|
||||
label: __("Conversion Factor")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -536,6 +543,7 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
"item_code": d.item_code,
|
||||
"delivery_date": d.delivery_date,
|
||||
"schedule_date": d.schedule_date,
|
||||
"conversion_factor": d.conversion_factor,
|
||||
"qty": d.qty,
|
||||
"rate": d.rate,
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ from frappe import _
|
||||
class QualityProcedure(NestedSet):
|
||||
nsm_parent_field = 'parent_quality_procedure'
|
||||
|
||||
def before_save(self):
|
||||
def on_save(self):
|
||||
for process in self.processes:
|
||||
if process.procedure:
|
||||
doc = frappe.get_doc("Quality Procedure", process.procedure)
|
||||
@@ -23,6 +23,11 @@ class QualityProcedure(NestedSet):
|
||||
|
||||
def after_insert(self):
|
||||
self.set_parent()
|
||||
#if Child is Added through Tree View.
|
||||
if self.parent_quality_procedure:
|
||||
parent_quality_procedure = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
|
||||
parent_quality_procedure.append("processes", {"procedure": self.name})
|
||||
parent_quality_procedure.save()
|
||||
|
||||
def on_trash(self):
|
||||
if self.parent_quality_procedure:
|
||||
|
||||
@@ -64,7 +64,8 @@ class ImportSupplierInvoice(Document):
|
||||
"buying_price_list": self.default_buying_price_list
|
||||
}
|
||||
|
||||
if not invoices_args.get("invoice_no", ''): return
|
||||
if not invoices_args.get("bill_no", ''):
|
||||
frappe.throw(_("Numero has not set in the XML file"))
|
||||
|
||||
supp_dict = get_supplier_details(file_content)
|
||||
invoices_args["destination_code"] = get_destination_code_from_file(file_content)
|
||||
|
||||
@@ -602,8 +602,9 @@ def get_transport_details(data, doc):
|
||||
data.transDocDate = frappe.utils.formatdate(doc.lr_date, 'dd/mm/yyyy')
|
||||
|
||||
if doc.gst_transporter_id:
|
||||
validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID')
|
||||
data.transporterId = doc.gst_transporter_id
|
||||
if doc.gst_transporter_id[0:2] != "88":
|
||||
validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID')
|
||||
data.transporterId = doc.gst_transporter_id
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertEqual(so.get("items")[-1].qty, 7)
|
||||
self.assertEqual(so.get("items")[-1].amount, 1400)
|
||||
self.assertEqual(so.status, 'To Deliver and Bill')
|
||||
|
||||
|
||||
def test_remove_item_in_update_child_qty_rate(self):
|
||||
so = make_sales_order(**{
|
||||
"item_list": [{
|
||||
@@ -372,7 +372,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
"docname": so.get("items")[0].name
|
||||
}])
|
||||
update_child_qty_rate('Sales Order', trans_item, so.name)
|
||||
|
||||
|
||||
so.reload()
|
||||
self.assertEqual(len(so.get("items")), 1)
|
||||
self.assertEqual(so.status, 'To Deliver and Bill')
|
||||
@@ -399,6 +399,23 @@ class TestSalesOrder(unittest.TestCase):
|
||||
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 2, 'docname': so.items[0].name}])
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
|
||||
|
||||
def test_update_child_qty_rate_perm(self):
|
||||
so = make_sales_order(item_code= "_Test Item", qty=4)
|
||||
|
||||
user = 'test@example.com'
|
||||
test_user = frappe.get_doc('User', user)
|
||||
test_user.add_roles("Accounts User")
|
||||
frappe.set_user(user)
|
||||
|
||||
# update qty
|
||||
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': so.items[0].name}])
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
|
||||
|
||||
# add new item
|
||||
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 100, 'qty' : 2}])
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_warehouse_user(self):
|
||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
|
||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "UOM",
|
||||
"options": "UOM",
|
||||
"print_hide": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@@ -229,7 +229,10 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
var me = this;
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
|
||||
if (item.serial_no && item.qty === item.serial_no.split(`\n`).length) {
|
||||
let serial_no_count = item.serial_no
|
||||
? item.serial_no.split(`\n`).filter(d => d).length : 0;
|
||||
|
||||
if (item.serial_no && item.qty === serial_no_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,10 @@ def place_order():
|
||||
|
||||
if is_stock_item:
|
||||
item_stock = get_qty_in_stock(item.item_code, "website_warehouse")
|
||||
if not cint(item_stock.in_stock):
|
||||
throw(_("{1} Not in Stock").format(item.item_code))
|
||||
if item.qty > item_stock.stock_qty[0][0]:
|
||||
throw(_("Only {0} in stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
|
||||
throw(_("Only {0} in Stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
|
||||
|
||||
sales_order.flags.ignore_permissions = True
|
||||
sales_order.insert()
|
||||
@@ -337,21 +339,17 @@ def set_price_list_and_rate(quotation, cart_settings):
|
||||
def _set_price_list(cart_settings, quotation=None):
|
||||
"""Set price list based on customer or shopping cart default"""
|
||||
from erpnext.accounts.party import get_default_price_list
|
||||
|
||||
# check if customer price list exists
|
||||
party_name = quotation.get("party_name") if quotation else get_party().get("name")
|
||||
selling_price_list = None
|
||||
if quotation and quotation.get("party_name"):
|
||||
selling_price_list = frappe.db.get_value('Customer', quotation.get("party_name"), 'default_price_list')
|
||||
|
||||
# else check for territory based price list
|
||||
# check if default customer price list exists
|
||||
if party_name:
|
||||
selling_price_list = get_default_price_list(frappe.get_doc("Customer", party_name))
|
||||
|
||||
# check default price list in shopping cart
|
||||
if not selling_price_list:
|
||||
selling_price_list = cart_settings.price_list
|
||||
|
||||
party_name = quotation.get("party_name") if quotation else get_party().get("name")
|
||||
|
||||
if not selling_price_list and party_name:
|
||||
selling_price_list = get_default_price_list(frappe.get_doc("Customer", party_name))
|
||||
|
||||
if quotation:
|
||||
quotation.selling_price_list = selling_price_list
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class ItemAttribute(Document):
|
||||
if self.numeric_values:
|
||||
validate_is_incremental(self, self.name, item.value, item.name)
|
||||
else:
|
||||
validate_item_attribute_value(attributes_list, self.name, item.value, item.name)
|
||||
validate_item_attribute_value(attributes_list, self.name, item.value, item.name, from_variant=False)
|
||||
|
||||
def validate_numeric(self):
|
||||
if self.numeric_values:
|
||||
|
||||
@@ -17,7 +17,7 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
// formatter for material request item
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; });
|
||||
function(doc) { return (doc.stock_qty<=doc.ordered_qty) ? "green" : "orange"; });
|
||||
|
||||
},
|
||||
|
||||
|
||||
@@ -119,11 +119,13 @@ def get_items_with_location_and_quantity(item_doc, item_location_map):
|
||||
if item_location.serial_no:
|
||||
serial_nos = '\n'.join(item_location.serial_no[0: cint(stock_qty)])
|
||||
|
||||
auto_set_serial_no = frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo")
|
||||
|
||||
locations.append(frappe._dict({
|
||||
'qty': qty,
|
||||
'stock_qty': stock_qty,
|
||||
'warehouse': item_location.warehouse,
|
||||
'serial_no': serial_nos,
|
||||
'serial_no': serial_nos if auto_set_serial_no else item_doc.serial_no,
|
||||
'batch_no': item_location.batch_no
|
||||
}))
|
||||
|
||||
@@ -206,6 +208,7 @@ def get_available_item_locations_for_batched_item(item_code, from_warehouses, re
|
||||
sle.batch_no = batch.name
|
||||
and sle.`item_code`=%(item_code)s
|
||||
and sle.`company` = %(company)s
|
||||
and batch.disabled = 0
|
||||
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
||||
{warehouse_condition}
|
||||
GROUP BY
|
||||
@@ -471,4 +474,4 @@ def update_common_item_properties(item, location):
|
||||
item.material_request = location.material_request
|
||||
item.serial_no = location.serial_no
|
||||
item.batch_no = location.batch_no
|
||||
item.material_request_item = location.material_request_item
|
||||
item.material_request_item = location.material_request_item
|
||||
|
||||
@@ -25,7 +25,7 @@ frappe.ui.form.on("Purchase Receipt", {
|
||||
|
||||
frm.custom_make_buttons = {
|
||||
'Stock Entry': 'Return',
|
||||
'Purchase Invoice': 'Invoice'
|
||||
'Purchase Invoice': 'Purchase Invoice'
|
||||
};
|
||||
|
||||
frm.set_query("expense_account", "items", function() {
|
||||
|
||||
@@ -178,7 +178,7 @@ class StockEntry(StockController):
|
||||
stock_items = self.get_stock_items()
|
||||
serialized_items = self.get_serialized_items()
|
||||
for item in self.get("items"):
|
||||
if item.qty and item.qty < 0:
|
||||
if flt(item.qty) and flt(item.qty) < 0:
|
||||
frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
|
||||
.format(item.idx, frappe.bold(item.item_code)))
|
||||
|
||||
@@ -497,7 +497,7 @@ class StockEntry(StockController):
|
||||
if raw_material_cost and self.purpose == "Manufacture":
|
||||
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
||||
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
||||
elif self.purpose == "Repack" and total_fg_qty:
|
||||
elif self.purpose == "Repack" and total_fg_qty and not d.set_basic_rate_manually:
|
||||
d.basic_rate = flt(raw_material_cost) / flt(total_fg_qty)
|
||||
d.basic_amount = d.basic_rate * d.qty
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"image",
|
||||
"image_view",
|
||||
"quantity_and_rate",
|
||||
"set_basic_rate_manually",
|
||||
"qty",
|
||||
"basic_rate",
|
||||
"basic_amount",
|
||||
@@ -490,12 +491,21 @@
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:parent.purpose===\"Repack\" && doc.t_warehouse",
|
||||
"fieldname": "set_basic_rate_manually",
|
||||
"fieldtype": "Check",
|
||||
"label": "Set Basic Rate Manually",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-19 12:34:09.836295",
|
||||
"modified": "2020-06-08 12:57:03.172887",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Entry Detail",
|
||||
|
||||
@@ -230,12 +230,12 @@ def get_valuation_method(item_code):
|
||||
|
||||
def get_fifo_rate(previous_stock_queue, qty):
|
||||
"""get FIFO (average) Rate from Queue"""
|
||||
if qty >= 0:
|
||||
if flt(qty) >= 0:
|
||||
total = sum(f[0] for f in previous_stock_queue)
|
||||
return sum(flt(f[0]) * flt(f[1]) for f in previous_stock_queue) / flt(total) if total else 0.0
|
||||
else:
|
||||
available_qty_for_outgoing, outgoing_cost = 0, 0
|
||||
qty_to_pop = abs(qty)
|
||||
qty_to_pop = abs(flt(qty))
|
||||
while qty_to_pop and previous_stock_queue:
|
||||
batch = previous_stock_queue[0]
|
||||
if 0 < batch[0] <= qty_to_pop:
|
||||
|
||||
@@ -193,14 +193,17 @@ class ItemConfigure {
|
||||
filtered_items_count === 1 ?
|
||||
filtered_items[0] : '';
|
||||
|
||||
// Allow Add to Cart if adding out of stock items enabled in Shopping Cart else check stock.
|
||||
const in_stock = product_info.allow_items_not_in_stock ? 1 : product_info.in_stock;
|
||||
const add_to_cart = `<a href data-action="btn_add_to_cart" data-item-code="${one_item}">${__('Add to cart')}</a>`;
|
||||
const product_action = in_stock ? add_to_cart : `<a style="color:#74808b;">${__('Not in Stock')}</a>`;
|
||||
|
||||
const item_add_to_cart = one_item ? `
|
||||
<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
|
||||
<div>
|
||||
<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
|
||||
</div>
|
||||
<a href data-action="btn_add_to_cart" data-item-code="${one_item}">
|
||||
${__('Add to cart')}
|
||||
</a>
|
||||
${product_action}
|
||||
</div>
|
||||
`: '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user