mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-21 14:09:19 +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() {
|
on_change: function() {
|
||||||
var me = frappe.treeview_settings['Account'].treeview;
|
var me = frappe.treeview_settings['Account'].treeview;
|
||||||
var company = me.page.fields_dict.company.get_value();
|
var company = me.page.fields_dict.company.get_value();
|
||||||
|
if (!company) {
|
||||||
|
frappe.throw(__("Please set a Company"));
|
||||||
|
}
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
method: "erpnext.accounts.doctype.account.account.get_root_company",
|
||||||
args: {
|
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)
|
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))
|
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],
|
# sort collection rule, first item on list will be lowest min_spent
|
||||||
key=lambda rule:rule.min_spent, reverse=True)
|
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):
|
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.tier_name = d.tier_name
|
||||||
lp_details.collection_factor = d.collection_factor
|
lp_details.collection_factor = d.collection_factor
|
||||||
else:
|
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})
|
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(si_original.get('loyalty_program'), customer.loyalty_program)
|
||||||
self.assertEqual(lpe.get('loyalty_program_tier'), customer.loyalty_program_tier)
|
self.assertEqual(lpe.get('loyalty_program_tier'), customer.loyalty_program_tier)
|
||||||
self.assertEqual(lpe.loyalty_points, earned_points)
|
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.setdefault(key, 0.0)
|
||||||
invoice_payment_amount_map[key] += reference.allocated_amount
|
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},
|
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
|
||||||
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
||||||
for term in payment_schedule:
|
for term in payment_schedule:
|
||||||
@@ -331,12 +331,14 @@ class PaymentEntry(AccountsController):
|
|||||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
||||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||||
else:
|
else:
|
||||||
outstanding = invoice_paid_amount_map.get(key)['outstanding']
|
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
|
||||||
|
|
||||||
if amount > outstanding:
|
if amount > outstanding:
|
||||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
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
|
if amount and outstanding:
|
||||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], 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]))
|
||||||
|
|
||||||
def set_status(self):
|
def set_status(self):
|
||||||
if self.docstatus == 2:
|
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):
|
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||||
references = []
|
references = []
|
||||||
for payment_term in payment_schedule:
|
for payment_term in payment_schedule:
|
||||||
references.append({
|
payment_term_outstanding = flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||||
'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.precision('payment_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
|
return references
|
||||||
|
|
||||||
|
|||||||
@@ -386,6 +386,50 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
self.assertEqual(so.items[1].is_free_item, 1)
|
self.assertEqual(so.items[1].is_free_item, 1)
|
||||||
self.assertEqual(so.items[1].item_code, "_Test Item 2")
|
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):
|
def make_pricing_rule(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ from six import string_types
|
|||||||
import frappe
|
import frappe
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
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.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 import _, throw
|
||||||
from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
|
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]
|
sum_qty, sum_amt = [0, 0]
|
||||||
doctype = doc.get('parenttype') or doc.doctype
|
doctype = doc.get('parenttype') or doc.doctype
|
||||||
|
|
||||||
date_field = ('transaction_date'
|
date_field = 'transaction_date' if frappe.get_meta(doctype).has_field('transaction_date') else 'posting_date'
|
||||||
if doc.get('transaction_date') else 'posting_date')
|
|
||||||
|
|
||||||
child_doctype = '{0} Item'.format(doctype)
|
child_doctype = '{0} Item'.format(doctype)
|
||||||
apply_on = frappe.scrub(pr_doc.get('apply_on'))
|
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':
|
if item_details.get("parenttype") == 'Sales Order':
|
||||||
item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
|
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):
|
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||||
if pricing_rule_args.get('item_code'):
|
if pricing_rule_args.get('item_code'):
|
||||||
items = [d.item_code for d in doc.items
|
items = [d.item_code for d in doc.items
|
||||||
|
|||||||
@@ -552,6 +552,8 @@ class SalesInvoice(SellingController):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for d in self.get('items'):
|
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')
|
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])):
|
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)
|
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):
|
def validate_item_code(self):
|
||||||
for d in self.get('items'):
|
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)
|
msgprint(_("Item Code required at Row No {0}").format(d.idx), raise_exception=True)
|
||||||
|
|
||||||
def validate_warehouse(self):
|
def validate_warehouse(self):
|
||||||
super(SalesInvoice, self).validate_warehouse()
|
super(SalesInvoice, self).validate_warehouse()
|
||||||
|
|
||||||
for d in self.get_item_list():
|
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))
|
frappe.throw(_("Warehouse required for stock Item {0}").format(d.item_code))
|
||||||
|
|
||||||
def validate_delivery_note(self):
|
def validate_delivery_note(self):
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ class ShippingRule(Document):
|
|||||||
shipping_amount = 0.0
|
shipping_amount = 0.0
|
||||||
by_value = False
|
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':
|
if self.calculate_based_on == 'Net Total':
|
||||||
value = doc.base_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,
|
"rate": tax_rate_detail.tax_withholding_rate,
|
||||||
"threshold": tax_rate_detail.single_threshold,
|
"threshold": tax_rate_detail.single_threshold,
|
||||||
"cumulative_threshold": tax_rate_detail.cumulative_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):
|
def get_tax_withholding_rates(tax_withholding, fiscal_year):
|
||||||
|
|||||||
@@ -169,9 +169,11 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
def append_subtotal_row(self, party):
|
def append_subtotal_row(self, party):
|
||||||
sub_total_row = self.total_row_map.get(party)
|
sub_total_row = self.total_row_map.get(party)
|
||||||
self.data.append(sub_total_row)
|
|
||||||
self.data.append({})
|
if sub_total_row:
|
||||||
self.update_sub_total_row(sub_total_row, 'Total')
|
self.data.append(sub_total_row)
|
||||||
|
self.data.append({})
|
||||||
|
self.update_sub_total_row(sub_total_row, 'Total')
|
||||||
|
|
||||||
def get_voucher_balance(self, gle):
|
def get_voucher_balance(self, gle):
|
||||||
if self.filters.get("sales_person"):
|
if self.filters.get("sales_person"):
|
||||||
@@ -232,7 +234,8 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
if self.filters.get('group_by_party'):
|
if self.filters.get('group_by_party'):
|
||||||
self.append_subtotal_row(self.previous_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):
|
def append_row(self, row):
|
||||||
self.allocate_future_payments(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_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
||||||
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
||||||
from (SELECT a.asset_category,
|
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
|
ds.depreciation_amount
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
@@ -115,9 +115,7 @@ def get_assets(filters):
|
|||||||
group by a.asset_category
|
group by a.asset_category
|
||||||
union
|
union
|
||||||
SELECT a.asset_category,
|
SELECT a.asset_category,
|
||||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
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
|
||||||
and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s)
|
|
||||||
then
|
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
a.opening_accumulated_depreciation
|
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)
|
to_date = add_months(start_date, months_to_add)
|
||||||
start_date = to_date
|
start_date = to_date
|
||||||
|
|
||||||
if to_date == get_first_day(to_date):
|
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||||
# if to_date is the first day, get the last day of previous month
|
to_date = add_days(to_date, -1)
|
||||||
to_date = add_days(to_date, -1)
|
|
||||||
|
|
||||||
if to_date <= year_end_date:
|
if to_date <= year_end_date:
|
||||||
# the normal case
|
# the normal case
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ class Asset(AccountsController):
|
|||||||
frappe.throw(_("Available-for-use Date should be after purchase date"))
|
frappe.throw(_("Available-for-use Date should be after purchase date"))
|
||||||
|
|
||||||
def validate_gross_and_purchase_amount(self):
|
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:
|
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. {}\
|
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.")
|
Please do not book expense of multiple assets against one single Asset.")
|
||||||
|
|||||||
@@ -1,559 +1,140 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "field:asset_name",
|
"autoname": "field:asset_name",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-10-19 16:50:22.879545",
|
"creation": "2017-10-19 16:50:22.879545",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "asset_name",
|
"fieldname": "asset_name",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Asset Name",
|
"label": "Asset Name",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Asset",
|
"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,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"unique": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "asset_name.asset_category",
|
"fetch_from": "asset_name.asset_category",
|
||||||
"fieldname": "asset_category",
|
"fieldname": "asset_category",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Asset Category"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "asset_name.item_code",
|
"fetch_from": "asset_name.item_code",
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Item Code"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "asset_name.item_name",
|
"fetch_from": "asset_name.item_name",
|
||||||
"fieldname": "item_name",
|
"fieldname": "item_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Item Name"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"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,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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": "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
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_6",
|
"fieldname": "section_break_6",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"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,
|
|
||||||
"fieldname": "maintenance_team",
|
"fieldname": "maintenance_team",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Maintenance Team",
|
"label": "Maintenance Team",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Asset Maintenance Team",
|
"options": "Asset Maintenance Team",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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",
|
"fieldname": "column_break_9",
|
||||||
"fieldtype": "Column Break",
|
"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",
|
"fetch_from": "maintenance_team.maintenance_manager",
|
||||||
"fieldname": "maintenance_manager",
|
"fieldname": "maintenance_manager",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"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",
|
"label": "Maintenance Manager",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "maintenance_team.maintenance_manager_name",
|
"fetch_from": "maintenance_team.maintenance_manager_name",
|
||||||
"fieldname": "maintenance_manager_name",
|
"fieldname": "maintenance_manager_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Maintenance Manager Name"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_8",
|
"fieldname": "section_break_8",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Tasks"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "asset_maintenance_tasks",
|
"fieldname": "asset_maintenance_tasks",
|
||||||
"fieldtype": "Table",
|
"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",
|
"label": "Maintenance Tasks",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Asset Maintenance Task",
|
"options": "Asset Maintenance Task",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_heading": 0,
|
"modified": "2020-05-28 20:28:32.993823",
|
||||||
"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",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Maintenance",
|
"name": "Asset Maintenance",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Quality Manager",
|
"role": "Quality Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Manufacturing User",
|
"role": "Manufacturing User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ class AssetMaintenance(Document):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def assign_tasks(asset_maintenance_name, assign_to_member, maintenance_task, next_due_date):
|
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 = {
|
args = {
|
||||||
'doctype' : 'Asset Maintenance',
|
'doctype' : 'Asset Maintenance',
|
||||||
'assign_to' : team_member,
|
'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):
|
def update_maintenance_log(asset_maintenance, item_code, item_name, task):
|
||||||
asset_maintenance_log = frappe.get_value("Asset Maintenance Log", {"asset_maintenance": asset_maintenance,
|
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:
|
if not asset_maintenance_log:
|
||||||
asset_maintenance_log = frappe.get_doc({
|
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,
|
"asset_name": asset_maintenance,
|
||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"item_name": item_name,
|
"item_name": item_name,
|
||||||
"task": task.maintenance_task,
|
"task": task.name,
|
||||||
"has_certificate": task.certificate_required,
|
"has_certificate": task.certificate_required,
|
||||||
"description": task.description,
|
"description": task.description,
|
||||||
"assign_to_name": task.assign_to_name,
|
"assign_to_name": task.assign_to_name,
|
||||||
|
|||||||
@@ -1,789 +1,190 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-10-23 16:58:44.424309",
|
"creation": "2017-10-23 16:58:44.424309",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Document",
|
"document_type": "Document",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "asset_maintenance",
|
"fieldname": "asset_maintenance",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Asset Maintenance",
|
||||||
"length": 0,
|
"options": "Asset Maintenance"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "",
|
|
||||||
"fieldname": "naming_series",
|
"fieldname": "naming_series",
|
||||||
"fieldtype": "Select",
|
"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",
|
"label": "Series",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "ACC-AML-.YYYY.-",
|
"options": "ACC-AML-.YYYY.-",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "asset_maintenance.asset_name",
|
"fetch_from": "asset_maintenance.asset_name",
|
||||||
"fieldname": "asset_name",
|
"fieldname": "asset_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Asset Name"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "column_break_2",
|
||||||
"fieldtype": "Column Break",
|
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "asset_maintenance.item_code",
|
"fetch_from": "asset_maintenance.item_code",
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Item Code"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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",
|
"fetch_from": "asset_maintenance.item_name",
|
||||||
"fieldname": "item_name",
|
"fieldname": "item_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Item Name"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_5",
|
"fieldname": "section_break_5",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "task",
|
"fieldname": "task",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Task",
|
||||||
"length": 0,
|
"options": "Asset Maintenance Task"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "task.maintenance_type",
|
"fetch_from": "task.maintenance_type",
|
||||||
"fieldname": "maintenance_type",
|
"fieldname": "maintenance_type",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Maintenance Type"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "task.periodicity",
|
"fetch_from": "task.periodicity",
|
||||||
"fieldname": "periodicity",
|
"fieldname": "periodicity",
|
||||||
"fieldtype": "Data",
|
"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",
|
"label": "Periodicity",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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",
|
"fetch_from": "task.assign_to_name",
|
||||||
"fieldname": "assign_to_name",
|
"fieldname": "assign_to_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Assign To"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_6",
|
"fieldname": "column_break_6",
|
||||||
"fieldtype": "Column Break",
|
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "task.next_due_date",
|
"fetch_from": "task.next_due_date",
|
||||||
"fieldname": "due_date",
|
"fieldname": "due_date",
|
||||||
"fieldtype": "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_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Due Date",
|
"label": "Due Date",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "completion_date",
|
"fieldname": "completion_date",
|
||||||
"fieldtype": "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_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Completion Date"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "maintenance_status",
|
"fieldname": "maintenance_status",
|
||||||
"fieldtype": "Select",
|
"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,
|
"in_standard_filter": 1,
|
||||||
"label": "Maintenance Status",
|
"label": "Maintenance Status",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Planned\nCompleted\nCancelled\nOverdue",
|
"options": "Planned\nCompleted\nCancelled\nOverdue",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_12",
|
"fieldname": "section_break_12",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"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,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "task.certificate_required",
|
"fetch_from": "task.certificate_required",
|
||||||
"fieldname": "has_certificate",
|
"fieldname": "has_certificate",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Has Certificate "
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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",
|
"depends_on": "eval:doc.has_certificate",
|
||||||
"fieldname": "certificate_attachement",
|
"fieldname": "certificate_attachement",
|
||||||
"fieldtype": "Attach",
|
"fieldtype": "Attach",
|
||||||
"hidden": 0,
|
"label": "Certificate"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_6",
|
"fieldname": "section_break_6",
|
||||||
"fieldtype": "Column Break",
|
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "task.description",
|
"fetch_from": "task.description",
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Read Only",
|
"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",
|
"label": "Description",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_9",
|
"fieldname": "column_break_9",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"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_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "actions_performed",
|
"fieldname": "actions_performed",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
"hidden": 0,
|
"label": "Actions performed"
|
||||||
"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_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Asset Maintenance Log",
|
"options": "Asset Maintenance Log",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"fetch_from": "task.maintenance_task",
|
||||||
"reqd": 0,
|
"fieldname": "task_name",
|
||||||
"search_index": 0,
|
"fieldtype": "Data",
|
||||||
"set_only_once": 0,
|
"in_preview": 1,
|
||||||
"translatable": 0,
|
"label": "Task Name",
|
||||||
"unique": 0
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2020-05-28 20:51:48.238397",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 14:44:51.457835",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Maintenance Log",
|
"name": "Asset Maintenance Log",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@@ -793,27 +194,17 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Manufacturing User",
|
"role": "Manufacturing User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "",
|
|
||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 1,
|
"track_seen": 1
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -7,5 +7,4 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class AssetMaintenanceTask(Document):
|
class AssetMaintenanceTask(Document):
|
||||||
def autoname(self):
|
pass
|
||||||
self.name = self.maintenance_task
|
|
||||||
|
|||||||
@@ -1056,7 +1056,7 @@
|
|||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-17 13:04:28.185197",
|
"modified": "2020-06-12 14:08:11.777120",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
@@ -1100,6 +1100,12 @@
|
|||||||
"read": 1,
|
"read": 1,
|
||||||
"role": "Purchase Manager",
|
"role": "Purchase Manager",
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"role": "Accounts User"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"search_fields": "status, transaction_date, supplier,grand_total",
|
"search_fields": "status, transaction_date, supplier,grand_total",
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ class PurchaseOrder(BuyingController):
|
|||||||
"compare_fields": [["project", "="], ["item_code", "="],
|
"compare_fields": [["project", "="], ["item_code", "="],
|
||||||
["uom", "="], ["conversion_factor", "="]],
|
["uom", "="], ["conversion_factor", "="]],
|
||||||
"is_child_table": True
|
"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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -183,6 +183,23 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
self.assertEquals(len(po.get('items')), 1)
|
self.assertEquals(len(po.get('items')), 1)
|
||||||
self.assertEqual(po.status, 'To Receive and Bill')
|
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):
|
def test_update_qty(self):
|
||||||
po = create_purchase_order()
|
po = create_purchase_order()
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import flt
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
@@ -54,15 +55,16 @@ def get_columns(filters):
|
|||||||
"width": 140
|
"width": 140
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Description"),
|
"label": _("Item"),
|
||||||
"fieldname": "description",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Link",
|
||||||
"width": 200
|
"options": "Item",
|
||||||
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Quantity"),
|
"label": _("Quantity"),
|
||||||
"fieldname": "quantity",
|
"fieldname": "quantity",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Float",
|
||||||
"width": 140
|
"width": 140
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -118,7 +120,7 @@ def get_columns(filters):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Purchase Order Amount(Company Currency)"),
|
"label": _("Purchase Order Amount(Company Currency)"),
|
||||||
"fieldname": "purchase_order_amt_usd",
|
"fieldname": "purchase_order_amt_in_company_currency",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"width": 140
|
"width": 140
|
||||||
},
|
},
|
||||||
@@ -175,17 +177,17 @@ def get_data(filters):
|
|||||||
"requesting_site": po.warehouse,
|
"requesting_site": po.warehouse,
|
||||||
"requestor": po.owner,
|
"requestor": po.owner,
|
||||||
"material_request_no": po.material_request,
|
"material_request_no": po.material_request,
|
||||||
"description": po.description,
|
"item_code": po.item_code,
|
||||||
"quantity": po.qty,
|
"quantity": flt(po.qty),
|
||||||
"unit_of_measurement": po.stock_uom,
|
"unit_of_measurement": po.stock_uom,
|
||||||
"status": po.status,
|
"status": po.status,
|
||||||
"purchase_order_date": po.transaction_date,
|
"purchase_order_date": po.transaction_date,
|
||||||
"purchase_order": po.parent,
|
"purchase_order": po.parent,
|
||||||
"supplier": po.supplier,
|
"supplier": po.supplier,
|
||||||
"estimated_cost": mr_record.get('amount'),
|
"estimated_cost": flt(mr_record.get('amount')),
|
||||||
"actual_cost": pi_records.get(po.name),
|
"actual_cost": flt(pi_records.get(po.name)),
|
||||||
"purchase_order_amt": po.amount,
|
"purchase_order_amt": flt(po.amount),
|
||||||
"purchase_order_amt_in_company_currency": po.base_amount,
|
"purchase_order_amt_in_company_currency": flt(po.base_amount),
|
||||||
"expected_delivery_date": po.schedule_date,
|
"expected_delivery_date": po.schedule_date,
|
||||||
"actual_delivery_date": pr_records.get(po.name)
|
"actual_delivery_date": pr_records.get(po.name)
|
||||||
}
|
}
|
||||||
@@ -198,9 +200,14 @@ def get_mapped_mr_details(conditions):
|
|||||||
SELECT
|
SELECT
|
||||||
par.transaction_date,
|
par.transaction_date,
|
||||||
par.per_ordered,
|
par.per_ordered,
|
||||||
|
par.owner,
|
||||||
child.name,
|
child.name,
|
||||||
child.parent,
|
child.parent,
|
||||||
child.amount
|
child.amount,
|
||||||
|
child.qty,
|
||||||
|
child.item_code,
|
||||||
|
child.uom,
|
||||||
|
par.status
|
||||||
FROM `tabMaterial Request` par, `tabMaterial Request Item` child
|
FROM `tabMaterial Request` par, `tabMaterial Request Item` child
|
||||||
WHERE
|
WHERE
|
||||||
par.per_ordered>=0
|
par.per_ordered>=0
|
||||||
@@ -217,7 +224,15 @@ def get_mapped_mr_details(conditions):
|
|||||||
procurement_record_details = dict(
|
procurement_record_details = dict(
|
||||||
material_request_date=record.transaction_date,
|
material_request_date=record.transaction_date,
|
||||||
material_request_no=record.parent,
|
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)
|
procurement_record_against_mr.append(procurement_record_details)
|
||||||
return mr_records, procurement_record_against_mr
|
return mr_records, procurement_record_against_mr
|
||||||
@@ -259,7 +274,7 @@ def get_po_entries(conditions):
|
|||||||
child.warehouse,
|
child.warehouse,
|
||||||
child.material_request,
|
child.material_request,
|
||||||
child.material_request_item,
|
child.material_request_item,
|
||||||
child.description,
|
child.item_code,
|
||||||
child.stock_uom,
|
child.stock_uom,
|
||||||
child.qty,
|
child.qty,
|
||||||
child.amount,
|
child.amount,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class TestProcurementTracker(unittest.TestCase):
|
|||||||
def test_result_for_procurement_tracker(self):
|
def test_result_for_procurement_tracker(self):
|
||||||
filters = {
|
filters = {
|
||||||
'company': '_Test Procurement Company',
|
'company': '_Test Procurement Company',
|
||||||
'cost_center': '_Test Cost Center - _TC'
|
'cost_center': 'Main - _TPC'
|
||||||
}
|
}
|
||||||
expected_data = self.generate_expected_data()
|
expected_data = self.generate_expected_data()
|
||||||
report = execute(filters)
|
report = execute(filters)
|
||||||
@@ -33,24 +33,27 @@ class TestProcurementTracker(unittest.TestCase):
|
|||||||
country="Pakistan"
|
country="Pakistan"
|
||||||
)).insert()
|
)).insert()
|
||||||
warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
|
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 = make_purchase_order(mr.name)
|
||||||
po.supplier = "_Test Supplier"
|
po.supplier = "_Test Supplier"
|
||||||
po.get("items")[0].cost_center = "_Test Cost Center - _TC"
|
po.get("items")[0].cost_center = "Main - _TPC"
|
||||||
po.submit()
|
po.submit()
|
||||||
pr = make_purchase_receipt(po.name)
|
pr = make_purchase_receipt(po.name)
|
||||||
|
pr.get("items")[0].cost_center = "Main - _TPC"
|
||||||
pr.submit()
|
pr.submit()
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
date_obj = datetime.date(datetime.now())
|
date_obj = datetime.date(datetime.now())
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
|
||||||
expected_data = {
|
expected_data = {
|
||||||
"material_request_date": date_obj,
|
"material_request_date": date_obj,
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "Main - _TPC",
|
||||||
"project": None,
|
"project": None,
|
||||||
"requesting_site": "_Test Procurement Warehouse - _TPC",
|
"requesting_site": "_Test Procurement Warehouse - _TPC",
|
||||||
"requestor": "Administrator",
|
"requestor": "Administrator",
|
||||||
"material_request_no": mr.name,
|
"material_request_no": mr.name,
|
||||||
"description": '_Test Item 1',
|
"item_code": '_Test Item',
|
||||||
"quantity": 10.0,
|
"quantity": 10.0,
|
||||||
"unit_of_measurement": "_Test UOM",
|
"unit_of_measurement": "_Test UOM",
|
||||||
"status": "To Bill",
|
"status": "To Bill",
|
||||||
@@ -58,9 +61,9 @@ class TestProcurementTracker(unittest.TestCase):
|
|||||||
"purchase_order": po.name,
|
"purchase_order": po.name,
|
||||||
"supplier": "_Test Supplier",
|
"supplier": "_Test Supplier",
|
||||||
"estimated_cost": 0.0,
|
"estimated_cost": 0.0,
|
||||||
"actual_cost": None,
|
"actual_cost": 0.0,
|
||||||
"purchase_order_amt": 5000.0,
|
"purchase_order_amt": po.net_total,
|
||||||
"purchase_order_amt_in_company_currency": 300000.0,
|
"purchase_order_amt_in_company_currency": po.base_net_total,
|
||||||
"expected_delivery_date": date_obj,
|
"expected_delivery_date": date_obj,
|
||||||
"actual_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.item_name = item.item_name
|
||||||
child_item.description = item.description
|
child_item.description = item.description
|
||||||
child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
|
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.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)
|
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||||
if not child_item.warehouse:
|
if not child_item.warehouse:
|
||||||
frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
|
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.item_name = item.item_name
|
||||||
child_item.description = item.description
|
child_item.description = item.description
|
||||||
child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
|
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.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_rate = 1 # Initiallize value will update in parent validation
|
||||||
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||||
return child_item
|
return child_item
|
||||||
@@ -1187,6 +1187,26 @@ def check_and_delete_children(parent, data):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
|
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)
|
data = json.loads(trans_items)
|
||||||
|
|
||||||
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
|
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
|
new_child_flag = False
|
||||||
if not d.get("docname"):
|
if not d.get("docname"):
|
||||||
new_child_flag = True
|
new_child_flag = True
|
||||||
if parent_doctype == "Sales Order":
|
check_permissions(parent, 'create')
|
||||||
child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
child_item = get_new_child_item()
|
||||||
if parent_doctype == "Purchase Order":
|
|
||||||
child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
|
|
||||||
else:
|
else:
|
||||||
|
check_permissions(parent, 'write')
|
||||||
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
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
|
continue
|
||||||
|
|
||||||
if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(child_item.delivered_qty):
|
validate_quantity(child_item, d)
|
||||||
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"))
|
|
||||||
|
|
||||||
child_item.qty = flt(d.get("qty"))
|
child_item.qty = flt(d.get("qty"))
|
||||||
precision = child_item.precision("rate") or 2
|
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:
|
else:
|
||||||
child_item.rate = flt(d.get("rate"))
|
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.price_list_rate):
|
||||||
if flt(child_item.rate) > 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
|
# if rate is greater than price_list_rate, set margin
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ class BuyingController(StockController):
|
|||||||
})
|
})
|
||||||
|
|
||||||
if not rm.rate:
|
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)
|
self.doctype, self.name, currency=self.company_currency, company=self.company)
|
||||||
|
|
||||||
rm.amount = qty * flt(rm.rate)
|
rm.amount = qty * flt(rm.rate)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ def validate_item_variant_attributes(item, args=None):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
attributes_list = attribute_values.get(attribute.lower(), [])
|
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):
|
def validate_is_incremental(numeric_attribute, attribute, value, item):
|
||||||
from_range = numeric_attribute.from_range
|
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),
|
.format(attribute, from_range, to_range, increment, item),
|
||||||
InvalidItemAttributeValueError, title=_('Invalid Attribute'))
|
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')
|
allow_rename_attribute_value = frappe.db.get_single_value('Item Variant Settings', 'allow_rename_attribute_value')
|
||||||
if allow_rename_attribute_value:
|
if allow_rename_attribute_value:
|
||||||
pass
|
pass
|
||||||
elif attribute_value not in attributes_list:
|
elif attribute_value not in attributes_list:
|
||||||
frappe.throw(_("The value {0} is already assigned to an exisiting Item {2}.").format(
|
if from_variant:
|
||||||
attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Rename Not Allowed'))
|
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):
|
def get_attribute_values(item):
|
||||||
if not frappe.flags.attribute_values:
|
if not frappe.flags.attribute_values:
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ class QualityInspectionNotSubmittedError(frappe.ValidationError): pass
|
|||||||
class StockController(AccountsController):
|
class StockController(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(StockController, self).validate()
|
super(StockController, self).validate()
|
||||||
self.validate_inspection()
|
if not self.get('is_return'):
|
||||||
|
self.validate_inspection()
|
||||||
self.validate_serialized_batch()
|
self.validate_serialized_batch()
|
||||||
self.validate_customer_provided_item()
|
self.validate_customer_provided_item()
|
||||||
|
|
||||||
@@ -224,7 +225,9 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
def check_expense_account(self, item):
|
def check_expense_account(self, item):
|
||||||
if not item.get("expense_account"):
|
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:
|
else:
|
||||||
is_expense_account = frappe.db.get_value("Account",
|
is_expense_account = frappe.db.get_value("Account",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2015-09-07 14:37:01.886859",
|
"creation": "2015-09-07 14:37:01.886859",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@@ -16,26 +17,33 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Course",
|
"label": "Course",
|
||||||
"options": "Course",
|
"options": "Course",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"fetch_from": "course.course_name",
|
||||||
"fieldname": "course_name",
|
"fieldname": "course_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Course Name",
|
"label": "Course Name",
|
||||||
"fetch_from": "course.course_name",
|
"read_only": 1,
|
||||||
"read_only":1
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "required",
|
"fieldname": "required",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Mandatory"
|
"label": "Mandatory",
|
||||||
|
"show_days": 1,
|
||||||
|
"show_seconds": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-06-12 12:42:12.845972",
|
"links": [],
|
||||||
|
"modified": "2020-06-09 18:56:10.213241",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Education",
|
"module": "Education",
|
||||||
"name": "Program Course",
|
"name": "Program Course",
|
||||||
|
|||||||
@@ -241,14 +241,17 @@ def get_order_taxes(shopify_order, shopify_settings):
|
|||||||
return taxes
|
return taxes
|
||||||
|
|
||||||
def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
|
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:
|
for shipping_charge in shipping_lines:
|
||||||
taxes.append({
|
for tax in shipping_charge.get("tax_lines"):
|
||||||
"charge_type": _("Actual"),
|
taxes.append({
|
||||||
"account_head": get_tax_account_head(shipping_charge),
|
"charge_type": _("Actual"),
|
||||||
"description": shipping_charge["title"],
|
"account_head": get_tax_account_head(tax),
|
||||||
"tax_amount": shipping_charge["price"],
|
"description": tax["title"],
|
||||||
"cost_center": shopify_settings.cost_center
|
"tax_amount": tax["price"],
|
||||||
})
|
"cost_center": shopify_settings.cost_center
|
||||||
|
})
|
||||||
|
|
||||||
return taxes
|
return taxes
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// 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) {
|
onload: function (frm) {
|
||||||
let reload_status = true;
|
let reload_status = true;
|
||||||
frappe.realtime.on("tally_migration_progress_update", function (data) {
|
frappe.realtime.on("tally_migration_progress_update", function (data) {
|
||||||
@@ -35,7 +37,17 @@ frappe.ui.form.on('Tally Migration', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function (frm) {
|
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.master_data && !frm.doc.is_master_data_imported) {
|
||||||
if (frm.doc.is_master_data_processed) {
|
if (frm.doc.is_master_data_processed) {
|
||||||
if (frm.doc.status != "Importing Master Data") {
|
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.day_book_data && !frm.doc.is_day_book_data_imported) {
|
||||||
if (frm.doc.is_day_book_data_processed) {
|
if (frm.doc.is_day_book_data_processed) {
|
||||||
if (frm.doc.status != "Importing Day Book Data") {
|
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) {
|
add_button: function (frm, label, method) {
|
||||||
frm.add_custom_button(
|
frm.add_custom_button(
|
||||||
label,
|
label,
|
||||||
@@ -71,5 +95,255 @@ frappe.ui.form.on('Tally Migration', {
|
|||||||
frm.reload_doc();
|
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",
|
"vouchers",
|
||||||
"accounts_section",
|
"accounts_section",
|
||||||
"default_warehouse",
|
"default_warehouse",
|
||||||
"round_off_account",
|
"default_round_off_account",
|
||||||
"column_break_21",
|
"column_break_21",
|
||||||
"default_cost_center",
|
"default_cost_center",
|
||||||
"day_book_section",
|
"day_book_section",
|
||||||
"day_book_data",
|
"day_book_data",
|
||||||
"column_break_27",
|
"column_break_27",
|
||||||
"is_day_book_data_processed",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -57,6 +62,7 @@
|
|||||||
"fieldname": "tally_creditors_account",
|
"fieldname": "tally_creditors_account",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Tally Creditors Account",
|
"label": "Tally Creditors Account",
|
||||||
|
"read_only_depends_on": "eval:doc.is_master_data_processed==1",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,6 +75,7 @@
|
|||||||
"fieldname": "tally_debtors_account",
|
"fieldname": "tally_debtors_account",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Tally Debtors Account",
|
"label": "Tally Debtors Account",
|
||||||
|
"read_only_depends_on": "eval:doc.is_master_data_processed==1",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -92,7 +99,7 @@
|
|||||||
"fieldname": "erpnext_company",
|
"fieldname": "erpnext_company",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "ERPNext Company",
|
"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",
|
"fieldname": "processed_files_section",
|
||||||
@@ -136,6 +143,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "is_master_data_imported",
|
"depends_on": "is_master_data_imported",
|
||||||
|
"description": "The accounts are set by the system automatically but do confirm these defaults",
|
||||||
"fieldname": "accounts_section",
|
"fieldname": "accounts_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Accounts"
|
"label": "Accounts"
|
||||||
@@ -146,12 +154,6 @@
|
|||||||
"label": "Default Warehouse",
|
"label": "Default Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "round_off_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"label": "Round Off Account",
|
|
||||||
"options": "Account"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_21",
|
"fieldname": "column_break_21",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
@@ -212,11 +214,47 @@
|
|||||||
"fieldname": "default_uom",
|
"fieldname": "default_uom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Default UOM",
|
"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": [],
|
"links": [],
|
||||||
"modified": "2020-04-16 13:03:28.894919",
|
"modified": "2020-04-28 00:29:18.039826",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Tally Migration",
|
"name": "Tally Migration",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import zipfile
|
import zipfile
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
@@ -15,18 +16,34 @@ from bs4 import BeautifulSoup as bs
|
|||||||
import frappe
|
import frappe
|
||||||
from erpnext import encode_company_abbr
|
from erpnext import encode_company_abbr
|
||||||
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
|
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 import _
|
||||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.naming import getseries, revert_series_if_last
|
from frappe.model.naming import getseries, revert_series_if_last
|
||||||
from frappe.utils.data import format_datetime
|
from frappe.utils.data import format_datetime
|
||||||
|
|
||||||
|
|
||||||
PRIMARY_ACCOUNT = "Primary"
|
PRIMARY_ACCOUNT = "Primary"
|
||||||
VOUCHER_CHUNK_SIZE = 500
|
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):
|
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):
|
def autoname(self):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
self.name = "Tally Migration on " + format_datetime(self.creation)
|
self.name = "Tally Migration on " + format_datetime(self.creation)
|
||||||
@@ -65,9 +82,17 @@ class TallyMigration(Document):
|
|||||||
"attached_to_name": self.name,
|
"attached_to_name": self.name,
|
||||||
"content": json.dumps(value),
|
"content": json.dumps(value),
|
||||||
"is_private": True
|
"is_private": True
|
||||||
}).insert()
|
})
|
||||||
|
try:
|
||||||
|
f.insert()
|
||||||
|
except frappe.DuplicateEntryError:
|
||||||
|
pass
|
||||||
setattr(self, key, f.file_url)
|
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 _process_master_data(self):
|
||||||
def get_company_name(collection):
|
def get_company_name(collection):
|
||||||
return collection.find_all("REMOTECMPINFO.LIST")[0].REMOTECMPNAME.string.strip()
|
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)
|
children, parents = get_children_and_parent_dict(accounts)
|
||||||
group_set = [acc[1] for acc in accounts if acc[2]]
|
group_set = [acc[1] for acc in accounts if acc[2]]
|
||||||
children, customers, suppliers = remove_parties(parents, children, group_set)
|
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:
|
for account in coa:
|
||||||
coa[account]["root_type"] = root_type_map[account]
|
coa[account]["root_type"] = root_type_map[account]
|
||||||
@@ -126,14 +155,18 @@ class TallyMigration(Document):
|
|||||||
def remove_parties(parents, children, group_set):
|
def remove_parties(parents, children, group_set):
|
||||||
customers, suppliers = set(), set()
|
customers, suppliers = set(), set()
|
||||||
for account in parents:
|
for account in parents:
|
||||||
|
found = False
|
||||||
if self.tally_creditors_account in parents[account]:
|
if self.tally_creditors_account in parents[account]:
|
||||||
children.pop(account, None)
|
found = True
|
||||||
if account not in group_set:
|
if account not in group_set:
|
||||||
suppliers.add(account)
|
suppliers.add(account)
|
||||||
elif self.tally_debtors_account in parents[account]:
|
if self.tally_debtors_account in parents[account]:
|
||||||
children.pop(account, None)
|
found = True
|
||||||
if account not in group_set:
|
if account not in group_set:
|
||||||
customers.add(account)
|
customers.add(account)
|
||||||
|
if found:
|
||||||
|
children.pop(account, None)
|
||||||
|
|
||||||
return children, customers, suppliers
|
return children, customers, suppliers
|
||||||
|
|
||||||
def traverse(tree, children, accounts, roots, group_set):
|
def traverse(tree, children, accounts, roots, group_set):
|
||||||
@@ -151,6 +184,7 @@ class TallyMigration(Document):
|
|||||||
parties, addresses = [], []
|
parties, addresses = [], []
|
||||||
for account in collection.find_all("LEDGER"):
|
for account in collection.find_all("LEDGER"):
|
||||||
party_type = None
|
party_type = None
|
||||||
|
links = []
|
||||||
if account.NAME.string.strip() in customers:
|
if account.NAME.string.strip() in customers:
|
||||||
party_type = "Customer"
|
party_type = "Customer"
|
||||||
parties.append({
|
parties.append({
|
||||||
@@ -161,7 +195,9 @@ class TallyMigration(Document):
|
|||||||
"territory": "All Territories",
|
"territory": "All Territories",
|
||||||
"customer_type": "Individual",
|
"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"
|
party_type = "Supplier"
|
||||||
parties.append({
|
parties.append({
|
||||||
"doctype": party_type,
|
"doctype": party_type,
|
||||||
@@ -170,6 +206,8 @@ class TallyMigration(Document):
|
|||||||
"supplier_group": "All Supplier Groups",
|
"supplier_group": "All Supplier Groups",
|
||||||
"supplier_type": "Individual",
|
"supplier_type": "Individual",
|
||||||
})
|
})
|
||||||
|
links.append({"link_doctype": party_type, "link_name": account["NAME"]})
|
||||||
|
|
||||||
if party_type:
|
if party_type:
|
||||||
address = "\n".join([a.string.strip() for a in account.find_all("ADDRESS")])
|
address = "\n".join([a.string.strip() for a in account.find_all("ADDRESS")])
|
||||||
addresses.append({
|
addresses.append({
|
||||||
@@ -183,7 +221,7 @@ class TallyMigration(Document):
|
|||||||
"mobile": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
|
"mobile": account.LEDGERPHONE.string.strip() if account.LEDGERPHONE else None,
|
||||||
"phone": 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,
|
"gstin": account.PARTYGSTIN.string.strip() if account.PARTYGSTIN else None,
|
||||||
"links": [{"link_doctype": party_type, "link_name": account["NAME"]}],
|
"links": links
|
||||||
})
|
})
|
||||||
return parties, addresses
|
return parties, addresses
|
||||||
|
|
||||||
@@ -242,12 +280,18 @@ class TallyMigration(Document):
|
|||||||
def create_company_and_coa(coa_file_url):
|
def create_company_and_coa(coa_file_url):
|
||||||
coa_file = frappe.get_doc("File", {"file_url": coa_file_url})
|
coa_file = frappe.get_doc("File", {"file_url": coa_file_url})
|
||||||
frappe.local.flags.ignore_chart_of_accounts = True
|
frappe.local.flags.ignore_chart_of_accounts = True
|
||||||
company = frappe.get_doc({
|
|
||||||
"doctype": "Company",
|
try:
|
||||||
"company_name": self.erpnext_company,
|
company = frappe.get_doc({
|
||||||
"default_currency": "INR",
|
"doctype": "Company",
|
||||||
"enable_perpetual_inventory": 0,
|
"company_name": self.erpnext_company,
|
||||||
}).insert()
|
"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
|
frappe.local.flags.ignore_chart_of_accounts = False
|
||||||
create_charts(company.name, custom_chart=json.loads(coa_file.get_content()))
|
create_charts(company.name, custom_chart=json.loads(coa_file.get_content()))
|
||||||
company.create_default_warehouses()
|
company.create_default_warehouses()
|
||||||
@@ -256,36 +300,35 @@ class TallyMigration(Document):
|
|||||||
parties_file = frappe.get_doc("File", {"file_url": parties_file_url})
|
parties_file = frappe.get_doc("File", {"file_url": parties_file_url})
|
||||||
for party in json.loads(parties_file.get_content()):
|
for party in json.loads(parties_file.get_content()):
|
||||||
try:
|
try:
|
||||||
frappe.get_doc(party).insert()
|
party_doc = frappe.get_doc(party)
|
||||||
|
party_doc.insert()
|
||||||
except:
|
except:
|
||||||
self.log(party)
|
self.log(party_doc)
|
||||||
addresses_file = frappe.get_doc("File", {"file_url": addresses_file_url})
|
addresses_file = frappe.get_doc("File", {"file_url": addresses_file_url})
|
||||||
for address in json.loads(addresses_file.get_content()):
|
for address in json.loads(addresses_file.get_content()):
|
||||||
try:
|
try:
|
||||||
frappe.get_doc(address).insert(ignore_mandatory=True)
|
address_doc = frappe.get_doc(address)
|
||||||
|
address_doc.insert(ignore_mandatory=True)
|
||||||
except:
|
except:
|
||||||
try:
|
self.log(address_doc)
|
||||||
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)
|
|
||||||
|
|
||||||
def create_items_uoms(items_file_url, uoms_file_url):
|
def create_items_uoms(items_file_url, uoms_file_url):
|
||||||
uoms_file = frappe.get_doc("File", {"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()):
|
for uom in json.loads(uoms_file.get_content()):
|
||||||
if not frappe.db.exists(uom):
|
if not frappe.db.exists(uom):
|
||||||
try:
|
try:
|
||||||
frappe.get_doc(uom).insert()
|
uom_doc = frappe.get_doc(uom)
|
||||||
|
uom_doc.insert()
|
||||||
except:
|
except:
|
||||||
self.log(uom)
|
self.log(uom_doc)
|
||||||
|
|
||||||
items_file = frappe.get_doc("File", {"file_url": items_file_url})
|
items_file = frappe.get_doc("File", {"file_url": items_file_url})
|
||||||
for item in json.loads(items_file.get_content()):
|
for item in json.loads(items_file.get_content()):
|
||||||
try:
|
try:
|
||||||
frappe.get_doc(item).insert()
|
item_doc = frappe.get_doc(item)
|
||||||
|
item_doc.insert()
|
||||||
except:
|
except:
|
||||||
self.log(item)
|
self.log(item_doc)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.publish("Import Master Data", _("Creating Company and Importing Chart of Accounts"), 1, 4)
|
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.publish("Import Master Data", _("Done"), 4, 4)
|
||||||
|
|
||||||
|
self.set_account_defaults()
|
||||||
self.is_master_data_imported = 1
|
self.is_master_data_imported = 1
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
except:
|
except:
|
||||||
self.publish("Import Master Data", _("Process Failed"), -1, 5)
|
self.publish("Import Master Data", _("Process Failed"), -1, 5)
|
||||||
|
frappe.db.rollback()
|
||||||
self.log()
|
self.log()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
@@ -323,7 +369,9 @@ class TallyMigration(Document):
|
|||||||
processed_voucher = function(voucher)
|
processed_voucher = function(voucher)
|
||||||
if processed_voucher:
|
if processed_voucher:
|
||||||
vouchers.append(processed_voucher)
|
vouchers.append(processed_voucher)
|
||||||
|
frappe.db.commit()
|
||||||
except:
|
except:
|
||||||
|
frappe.db.rollback()
|
||||||
self.log(voucher)
|
self.log(voucher)
|
||||||
return vouchers
|
return vouchers
|
||||||
|
|
||||||
@@ -349,6 +397,7 @@ class TallyMigration(Document):
|
|||||||
journal_entry = {
|
journal_entry = {
|
||||||
"doctype": "Journal Entry",
|
"doctype": "Journal Entry",
|
||||||
"tally_guid": voucher.GUID.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(),
|
"posting_date": voucher.DATE.string.strip(),
|
||||||
"company": self.erpnext_company,
|
"company": self.erpnext_company,
|
||||||
"accounts": accounts,
|
"accounts": accounts,
|
||||||
@@ -377,6 +426,7 @@ class TallyMigration(Document):
|
|||||||
"doctype": doctype,
|
"doctype": doctype,
|
||||||
party_field: voucher.PARTYNAME.string.strip(),
|
party_field: voucher.PARTYNAME.string.strip(),
|
||||||
"tally_guid": voucher.GUID.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(),
|
"posting_date": voucher.DATE.string.strip(),
|
||||||
"due_date": voucher.DATE.string.strip(),
|
"due_date": voucher.DATE.string.strip(),
|
||||||
"items": get_voucher_items(voucher, doctype),
|
"items": get_voucher_items(voucher, doctype),
|
||||||
@@ -468,14 +518,21 @@ class TallyMigration(Document):
|
|||||||
oldest_year = new_year
|
oldest_year = new_year
|
||||||
|
|
||||||
def create_custom_fields(doctypes):
|
def create_custom_fields(doctypes):
|
||||||
for doctype in doctypes:
|
tally_guid_df = {
|
||||||
df = {
|
"fieldtype": "Data",
|
||||||
"fieldtype": "Data",
|
"fieldname": "tally_guid",
|
||||||
"fieldname": "tally_guid",
|
"read_only": 1,
|
||||||
"read_only": 1,
|
"label": "Tally GUID"
|
||||||
"label": "Tally GUID"
|
}
|
||||||
}
|
tally_voucher_no_df = {
|
||||||
create_custom_field(doctype, 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():
|
def create_price_list():
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
@@ -490,7 +547,7 @@ class TallyMigration(Document):
|
|||||||
try:
|
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_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("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_file = frappe.get_doc("File", {"file_url": self.vouchers})
|
||||||
vouchers = json.loads(vouchers_file.get_content())
|
vouchers = json.loads(vouchers_file.get_content())
|
||||||
@@ -521,11 +578,14 @@ class TallyMigration(Document):
|
|||||||
|
|
||||||
for index, voucher in enumerate(chunk, start=start):
|
for index, voucher in enumerate(chunk, start=start):
|
||||||
try:
|
try:
|
||||||
doc = frappe.get_doc(voucher).insert()
|
voucher_doc = frappe.get_doc(voucher)
|
||||||
doc.submit()
|
voucher_doc.insert()
|
||||||
|
voucher_doc.submit()
|
||||||
self.publish("Importing Vouchers", _("{} of {}").format(index, total), index, total)
|
self.publish("Importing Vouchers", _("{} of {}").format(index, total), index, total)
|
||||||
|
frappe.db.commit()
|
||||||
except:
|
except:
|
||||||
self.log(voucher)
|
frappe.db.rollback()
|
||||||
|
self.log(voucher_doc)
|
||||||
|
|
||||||
if is_last:
|
if is_last:
|
||||||
self.status = ""
|
self.status = ""
|
||||||
@@ -551,9 +611,22 @@ class TallyMigration(Document):
|
|||||||
frappe.enqueue_doc(self.doctype, self.name, "_import_day_book_data", queue="long", timeout=3600)
|
frappe.enqueue_doc(self.doctype, self.name, "_import_day_book_data", queue="long", timeout=3600)
|
||||||
|
|
||||||
def log(self, data=None):
|
def log(self, data=None):
|
||||||
data = data or self.status
|
if isinstance(data, frappe.model.document.Document):
|
||||||
message = "\n".join(["Data:", json.dumps(data, default=str, indent=4), "--" * 50, "\nException:", traceback.format_exc()])
|
if sys.exc_info()[1].__class__ != frappe.DuplicateEntryError:
|
||||||
return frappe.log_error(title="Tally Migration Error", message=message)
|
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=""):
|
def set_status(self, status=""):
|
||||||
self.status = status
|
self.status = status
|
||||||
|
|||||||
@@ -113,13 +113,13 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
employee: function (frm) {
|
employee: function (frm) {
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
return frappe.call({
|
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: {
|
args: {
|
||||||
"employee": frm.doc.employee,
|
"employee": frm.doc.employee,
|
||||||
"posting_date": frm.doc.posting_date
|
"posting_date": frm.doc.posting_date
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
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",
|
"column_break_11",
|
||||||
"advance_amount",
|
"advance_amount",
|
||||||
"paid_amount",
|
"paid_amount",
|
||||||
"due_advance_amount",
|
"pending_amount",
|
||||||
"claimed_amount",
|
"claimed_amount",
|
||||||
"return_amount",
|
"return_amount",
|
||||||
"section_break_7",
|
"section_break_7",
|
||||||
@@ -101,14 +101,6 @@
|
|||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"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",
|
"fieldname": "claimed_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
@@ -169,11 +161,25 @@
|
|||||||
"label": "Returned Amount",
|
"label": "Returned Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"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,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-15 19:04:07.044505",
|
"modified": "2020-06-12 12:42:39.833818",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Advance",
|
"name": "Employee Advance",
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class EmployeeAdvance(Document):
|
|||||||
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@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", \
|
employee_due_amount = frappe.get_all("Employee Advance", \
|
||||||
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
filters = {"employee":employee, "docstatus":1, "posting_date":("<=", posting_date)}, \
|
||||||
fields = ["advance_amount", "paid_amount"])
|
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) {
|
frm.set_query("account_head", "taxes", function(doc) {
|
||||||
return {
|
return {
|
||||||
filters: [
|
filters: [
|
||||||
|
|||||||
@@ -101,8 +101,16 @@ class BOM(WebsiteGenerator):
|
|||||||
if self.routing:
|
if self.routing:
|
||||||
self.set("operations", [])
|
self.set("operations", [])
|
||||||
for d in frappe.get_all("BOM Operation", fields = ["*"],
|
for d in frappe.get_all("BOM Operation", fields = ["*"],
|
||||||
filters = {'parenttype': 'Routing', 'parent': self.routing}):
|
filters = {'parenttype': 'Routing', 'parent': self.routing}, order_by="idx"):
|
||||||
child = self.append('operations', d)
|
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)
|
child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)
|
||||||
|
|
||||||
def validate_rm_item(self, item):
|
def validate_rm_item(self, item):
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "eval:parent.doctype == 'BOM'",
|
||||||
"fieldname": "base_hour_rate",
|
"fieldname": "base_hour_rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Base Hour Rate(Company Currency)",
|
"label": "Base Hour Rate(Company Currency)",
|
||||||
@@ -87,6 +88,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "5",
|
"default": "5",
|
||||||
|
"depends_on": "eval:parent.doctype == 'BOM'",
|
||||||
"fieldname": "base_operating_cost",
|
"fieldname": "base_operating_cost",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Operating Cost(Company Currency)",
|
"label": "Operating Cost(Company Currency)",
|
||||||
@@ -108,8 +110,8 @@
|
|||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-07-16 22:35:55.374037",
|
"modified": "2020-06-16 17:01:11.128420",
|
||||||
"modified_by": "govindsmenokee@gmail.com",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM Operation",
|
"name": "BOM Operation",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ frappe.ui.form.on('BOM Operation', {
|
|||||||
name: d.workstation
|
name: d.workstation
|
||||||
},
|
},
|
||||||
callback: function (data) {
|
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);
|
frappe.model.set_value(d.doctype, d.name, "hour_rate", data.message.hour_rate);
|
||||||
frm.events.calculate_operating_cost(frm, d);
|
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_price_list_currency_in_bom
|
||||||
erpnext.patches.v12_0.update_uom_conversion_factor
|
erpnext.patches.v12_0.update_uom_conversion_factor
|
||||||
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
|
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 frappe
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from frappe.utils import cint
|
||||||
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
|
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
|
||||||
|
|
||||||
def get_field_filter_data():
|
def get_field_filter_data():
|
||||||
@@ -265,6 +266,8 @@ def get_next_attribute_and_values(item_code, selected_attributes):
|
|||||||
else:
|
else:
|
||||||
product_info = None
|
product_info = None
|
||||||
|
|
||||||
|
product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'next_attribute': next_attribute,
|
'next_attribute': next_attribute,
|
||||||
'valid_options_for_attributes': valid_options_for_attributes,
|
'valid_options_for_attributes': valid_options_for_attributes,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||||
setup: function() {
|
setup: function() {
|
||||||
this._super();
|
this._super();
|
||||||
frappe.flags.hide_serial_batch_dialog = true;
|
|
||||||
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
|
frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) {
|
||||||
var item = frappe.get_doc(cdt, cdn);
|
var item = frappe.get_doc(cdt, cdn);
|
||||||
var has_margin_field = frappe.meta.has_field(cdt, 'margin_type');
|
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)
|
if (show_batch_dialog)
|
||||||
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
return frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"])
|
||||||
.then((r) => {
|
.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;
|
frappe.flags.hide_serial_batch_dialog = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -879,7 +879,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
shipping_rule: function() {
|
shipping_rule: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.shipping_rule && this.frm.doc.shipping_address) {
|
if(this.frm.doc.shipping_rule) {
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
doc: this.frm.doc,
|
doc: this.frm.doc,
|
||||||
method: "apply_shipping_rule",
|
method: "apply_shipping_rule",
|
||||||
|
|||||||
@@ -487,7 +487,14 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
fieldtype: 'Date',
|
fieldtype: 'Date',
|
||||||
fieldname: frm.doc.doctype == 'Sales Order' ? "delivery_date" : "schedule_date",
|
fieldname: frm.doc.doctype == 'Sales Order' ? "delivery_date" : "schedule_date",
|
||||||
in_list_view: 1,
|
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,
|
"item_code": d.item_code,
|
||||||
"delivery_date": d.delivery_date,
|
"delivery_date": d.delivery_date,
|
||||||
"schedule_date": d.schedule_date,
|
"schedule_date": d.schedule_date,
|
||||||
|
"conversion_factor": d.conversion_factor,
|
||||||
"qty": d.qty,
|
"qty": d.qty,
|
||||||
"rate": d.rate,
|
"rate": d.rate,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from frappe import _
|
|||||||
class QualityProcedure(NestedSet):
|
class QualityProcedure(NestedSet):
|
||||||
nsm_parent_field = 'parent_quality_procedure'
|
nsm_parent_field = 'parent_quality_procedure'
|
||||||
|
|
||||||
def before_save(self):
|
def on_save(self):
|
||||||
for process in self.processes:
|
for process in self.processes:
|
||||||
if process.procedure:
|
if process.procedure:
|
||||||
doc = frappe.get_doc("Quality Procedure", process.procedure)
|
doc = frappe.get_doc("Quality Procedure", process.procedure)
|
||||||
@@ -23,6 +23,11 @@ class QualityProcedure(NestedSet):
|
|||||||
|
|
||||||
def after_insert(self):
|
def after_insert(self):
|
||||||
self.set_parent()
|
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):
|
def on_trash(self):
|
||||||
if self.parent_quality_procedure:
|
if self.parent_quality_procedure:
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ class ImportSupplierInvoice(Document):
|
|||||||
"buying_price_list": self.default_buying_price_list
|
"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)
|
supp_dict = get_supplier_details(file_content)
|
||||||
invoices_args["destination_code"] = get_destination_code_from_file(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')
|
data.transDocDate = frappe.utils.formatdate(doc.lr_date, 'dd/mm/yyyy')
|
||||||
|
|
||||||
if doc.gst_transporter_id:
|
if doc.gst_transporter_id:
|
||||||
validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID')
|
if doc.gst_transporter_id[0:2] != "88":
|
||||||
data.transporterId = doc.gst_transporter_id
|
validate_gstin_check_digit(doc.gst_transporter_id, label='GST Transporter ID')
|
||||||
|
data.transporterId = doc.gst_transporter_id
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@@ -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}])
|
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)
|
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):
|
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 1 - _TC", "test@example.com")
|
||||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
||||||
|
|||||||
@@ -210,6 +210,7 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "UOM",
|
"label": "UOM",
|
||||||
"options": "UOM",
|
"options": "UOM",
|
||||||
|
"print_hide": 0,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -229,7 +229,10 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
|||||||
var me = this;
|
var me = this;
|
||||||
var item = frappe.get_doc(cdt, cdn);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ def place_order():
|
|||||||
|
|
||||||
if is_stock_item:
|
if is_stock_item:
|
||||||
item_stock = get_qty_in_stock(item.item_code, "website_warehouse")
|
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]:
|
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.flags.ignore_permissions = True
|
||||||
sales_order.insert()
|
sales_order.insert()
|
||||||
@@ -337,21 +339,17 @@ def set_price_list_and_rate(quotation, cart_settings):
|
|||||||
def _set_price_list(cart_settings, quotation=None):
|
def _set_price_list(cart_settings, quotation=None):
|
||||||
"""Set price list based on customer or shopping cart default"""
|
"""Set price list based on customer or shopping cart default"""
|
||||||
from erpnext.accounts.party import get_default_price_list
|
from erpnext.accounts.party import get_default_price_list
|
||||||
|
party_name = quotation.get("party_name") if quotation else get_party().get("name")
|
||||||
# check if customer price list exists
|
|
||||||
selling_price_list = None
|
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:
|
if not selling_price_list:
|
||||||
selling_price_list = cart_settings.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:
|
if quotation:
|
||||||
quotation.selling_price_list = selling_price_list
|
quotation.selling_price_list = selling_price_list
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ItemAttribute(Document):
|
|||||||
if self.numeric_values:
|
if self.numeric_values:
|
||||||
validate_is_incremental(self, self.name, item.value, item.name)
|
validate_is_incremental(self, self.name, item.value, item.name)
|
||||||
else:
|
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):
|
def validate_numeric(self):
|
||||||
if self.numeric_values:
|
if self.numeric_values:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ frappe.ui.form.on('Material Request', {
|
|||||||
|
|
||||||
// formatter for material request item
|
// formatter for material request item
|
||||||
frm.set_indicator_formatter('item_code',
|
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:
|
if item_location.serial_no:
|
||||||
serial_nos = '\n'.join(item_location.serial_no[0: cint(stock_qty)])
|
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({
|
locations.append(frappe._dict({
|
||||||
'qty': qty,
|
'qty': qty,
|
||||||
'stock_qty': stock_qty,
|
'stock_qty': stock_qty,
|
||||||
'warehouse': item_location.warehouse,
|
'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
|
'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
|
sle.batch_no = batch.name
|
||||||
and sle.`item_code`=%(item_code)s
|
and sle.`item_code`=%(item_code)s
|
||||||
and sle.`company` = %(company)s
|
and sle.`company` = %(company)s
|
||||||
|
and batch.disabled = 0
|
||||||
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
|
||||||
{warehouse_condition}
|
{warehouse_condition}
|
||||||
GROUP BY
|
GROUP BY
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ frappe.ui.form.on("Purchase Receipt", {
|
|||||||
|
|
||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Stock Entry': 'Return',
|
'Stock Entry': 'Return',
|
||||||
'Purchase Invoice': 'Invoice'
|
'Purchase Invoice': 'Purchase Invoice'
|
||||||
};
|
};
|
||||||
|
|
||||||
frm.set_query("expense_account", "items", function() {
|
frm.set_query("expense_account", "items", function() {
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ class StockEntry(StockController):
|
|||||||
stock_items = self.get_stock_items()
|
stock_items = self.get_stock_items()
|
||||||
serialized_items = self.get_serialized_items()
|
serialized_items = self.get_serialized_items()
|
||||||
for item in self.get("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")
|
frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
|
||||||
.format(item.idx, frappe.bold(item.item_code)))
|
.format(item.idx, frappe.bold(item.item_code)))
|
||||||
|
|
||||||
@@ -497,7 +497,7 @@ class StockEntry(StockController):
|
|||||||
if raw_material_cost and self.purpose == "Manufacture":
|
if raw_material_cost and self.purpose == "Manufacture":
|
||||||
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
||||||
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
||||||
elif self.purpose == "Repack" and total_fg_qty:
|
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_rate = flt(raw_material_cost) / flt(total_fg_qty)
|
||||||
d.basic_amount = d.basic_rate * d.qty
|
d.basic_amount = d.basic_rate * d.qty
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"image",
|
"image",
|
||||||
"image_view",
|
"image_view",
|
||||||
"quantity_and_rate",
|
"quantity_and_rate",
|
||||||
|
"set_basic_rate_manually",
|
||||||
"qty",
|
"qty",
|
||||||
"basic_rate",
|
"basic_rate",
|
||||||
"basic_amount",
|
"basic_amount",
|
||||||
@@ -490,12 +491,21 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 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,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-19 12:34:09.836295",
|
"modified": "2020-06-08 12:57:03.172887",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Entry Detail",
|
"name": "Stock Entry Detail",
|
||||||
|
|||||||
@@ -230,12 +230,12 @@ def get_valuation_method(item_code):
|
|||||||
|
|
||||||
def get_fifo_rate(previous_stock_queue, qty):
|
def get_fifo_rate(previous_stock_queue, qty):
|
||||||
"""get FIFO (average) Rate from Queue"""
|
"""get FIFO (average) Rate from Queue"""
|
||||||
if qty >= 0:
|
if flt(qty) >= 0:
|
||||||
total = sum(f[0] for f in previous_stock_queue)
|
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
|
return sum(flt(f[0]) * flt(f[1]) for f in previous_stock_queue) / flt(total) if total else 0.0
|
||||||
else:
|
else:
|
||||||
available_qty_for_outgoing, outgoing_cost = 0, 0
|
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:
|
while qty_to_pop and previous_stock_queue:
|
||||||
batch = previous_stock_queue[0]
|
batch = previous_stock_queue[0]
|
||||||
if 0 < batch[0] <= qty_to_pop:
|
if 0 < batch[0] <= qty_to_pop:
|
||||||
|
|||||||
@@ -193,14 +193,17 @@ class ItemConfigure {
|
|||||||
filtered_items_count === 1 ?
|
filtered_items_count === 1 ?
|
||||||
filtered_items[0] : '';
|
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 ? `
|
const item_add_to_cart = one_item ? `
|
||||||
<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
|
<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
|
||||||
<div>
|
<div>
|
||||||
<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
|
<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
|
||||||
</div>
|
</div>
|
||||||
<a href data-action="btn_add_to_cart" data-item-code="${one_item}">
|
${product_action}
|
||||||
${__('Add to cart')}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
`: '';
|
`: '';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user