Merge branch 'develop' into purchase-invoice-payment-terms
This commit is contained in:
commit
6d2bcd2404
@ -7,7 +7,7 @@ frappe.ui.form.on('Accounting Dimension', {
|
||||
frm.set_query('document_type', () => {
|
||||
let invalid_doctypes = frappe.model.core_doctypes_list;
|
||||
invalid_doctypes.push('Accounting Dimension', 'Project',
|
||||
'Cost Center', 'Accounting Dimension Detail');
|
||||
'Cost Center', 'Accounting Dimension Detail', 'Company');
|
||||
|
||||
return {
|
||||
filters: {
|
||||
|
@ -19,7 +19,7 @@ class AccountingDimension(Document):
|
||||
|
||||
def validate(self):
|
||||
if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project',
|
||||
'Cost Center', 'Accounting Dimension Detail') :
|
||||
'Cost Center', 'Accounting Dimension Detail', 'Company') :
|
||||
|
||||
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
|
||||
frappe.throw(msg)
|
||||
|
@ -158,8 +158,11 @@ class TestBudget(unittest.TestCase):
|
||||
set_total_expense_zero(nowdate(), "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
month = now_datetime().month
|
||||
if month > 10:
|
||||
month = 10
|
||||
|
||||
for i in range(now_datetime().month):
|
||||
for i in range(month):
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
|
||||
|
||||
@ -177,8 +180,11 @@ class TestBudget(unittest.TestCase):
|
||||
set_total_expense_zero(nowdate(), "project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
month = now_datetime().month
|
||||
if month > 10:
|
||||
month = 10
|
||||
|
||||
for i in range(now_datetime().month):
|
||||
for i in range(month):
|
||||
jv = make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", 20000, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True, project="_Test Project")
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
"column_break_9",
|
||||
"update_stock",
|
||||
"ignore_pricing_rule",
|
||||
"hide_unavailable_items",
|
||||
"warehouse",
|
||||
"campaign",
|
||||
"company_address",
|
||||
@ -307,13 +308,19 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Update Stock",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "hide_unavailable_items",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hide Unavailable Items"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-20 13:16:50.665081",
|
||||
"modified": "2020-10-29 13:18:38.795925",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
@ -504,10 +504,10 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
|
||||
"depends_on": "eval:in_list(['Discount Percentage'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
|
||||
"fieldname": "apply_discount_on_rate",
|
||||
"fieldtype": "Check",
|
||||
"label": "Apply Discount on Rate"
|
||||
"label": "Apply Discount on Discounted Rate"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@ -563,7 +563,7 @@
|
||||
"icon": "fa fa-gift",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2020-08-26 12:24:44.740734",
|
||||
"modified": "2020-10-28 16:53:14.416172",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Pricing Rule",
|
||||
|
@ -60,6 +60,15 @@ class PricingRule(Document):
|
||||
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
|
||||
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
|
||||
|
||||
if self.apply_discount_on_rate:
|
||||
if not self.priority:
|
||||
throw(_("As the field {0} is enabled, the field {1} is mandatory.")
|
||||
.format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
|
||||
|
||||
if self.priority and cint(self.priority) == 1:
|
||||
throw(_("As the field {0} is enabled, the value of the field {1} should be more than 1.")
|
||||
.format(frappe.bold("Apply Discount on Discounted Rate"), frappe.bold("Priority")))
|
||||
|
||||
def validate_applicable_for_selling_or_buying(self):
|
||||
if not self.selling and not self.buying:
|
||||
throw(_("Atleast one of the Selling or Buying must be selected"))
|
||||
@ -226,12 +235,11 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
||||
|
||||
item_details = frappe._dict({
|
||||
"doctype": args.doctype,
|
||||
"has_margin": False,
|
||||
"name": args.name,
|
||||
"parent": args.parent,
|
||||
"parenttype": args.parenttype,
|
||||
"child_docname": args.get('child_docname'),
|
||||
"discount_percentage_on_rate": [],
|
||||
"discount_amount_on_rate": []
|
||||
"child_docname": args.get('child_docname')
|
||||
})
|
||||
|
||||
if args.ignore_pricing_rule or not args.item_code:
|
||||
@ -279,6 +287,10 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
||||
else:
|
||||
get_product_discount_rule(pricing_rule, item_details, args, doc)
|
||||
|
||||
if not item_details.get("has_margin"):
|
||||
item_details.margin_type = None
|
||||
item_details.margin_rate_or_amount = 0.0
|
||||
|
||||
item_details.has_pricing_rule = 1
|
||||
|
||||
item_details.pricing_rules = frappe.as_json([d.pricing_rule for d in rules])
|
||||
@ -330,13 +342,11 @@ def get_pricing_rule_details(args, pricing_rule):
|
||||
def apply_price_discount_rule(pricing_rule, item_details, args):
|
||||
item_details.pricing_rule_for = pricing_rule.rate_or_discount
|
||||
|
||||
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
|
||||
if ((pricing_rule.margin_type in ['Amount', 'Percentage'] and pricing_rule.currency == args.currency)
|
||||
or (pricing_rule.margin_type == 'Percentage')):
|
||||
item_details.margin_type = pricing_rule.margin_type
|
||||
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
|
||||
else:
|
||||
item_details.margin_type = None
|
||||
item_details.margin_rate_or_amount = 0.0
|
||||
item_details.has_margin = True
|
||||
|
||||
if pricing_rule.rate_or_discount == 'Rate':
|
||||
pricing_rule_rate = 0.0
|
||||
@ -351,9 +361,9 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
|
||||
if pricing_rule.rate_or_discount != apply_on: continue
|
||||
|
||||
field = frappe.scrub(apply_on)
|
||||
if pricing_rule.apply_discount_on_rate:
|
||||
discount_field = "{0}_on_rate".format(field)
|
||||
item_details[discount_field].append(pricing_rule.get(field, 0))
|
||||
if pricing_rule.apply_discount_on_rate and item_details.get("discount_percentage"):
|
||||
# Apply discount on discounted rate
|
||||
item_details[field] += ((100 - item_details[field]) * (pricing_rule.get(field, 0) / 100))
|
||||
else:
|
||||
if field not in item_details:
|
||||
item_details.setdefault(field, 0)
|
||||
@ -361,14 +371,6 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
|
||||
item_details[field] += (pricing_rule.get(field, 0)
|
||||
if pricing_rule else args.get(field, 0))
|
||||
|
||||
def set_discount_amount(rate, item_details):
|
||||
for field in ['discount_percentage_on_rate', 'discount_amount_on_rate']:
|
||||
for d in item_details.get(field):
|
||||
dis_amount = (rate * d / 100
|
||||
if field == 'discount_percentage_on_rate' else d)
|
||||
rate -= dis_amount
|
||||
item_details.rate = rate
|
||||
|
||||
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
|
||||
from erpnext.accounts.doctype.pricing_rule.utils import (get_applied_pricing_rules,
|
||||
get_pricing_rule_items)
|
||||
|
@ -385,7 +385,7 @@ class TestPricingRule(unittest.TestCase):
|
||||
so.load_from_db()
|
||||
self.assertEqual(so.items[1].is_free_item, 1)
|
||||
self.assertEqual(so.items[1].item_code, "_Test Item 2")
|
||||
|
||||
|
||||
def test_cumulative_pricing_rule(self):
|
||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Cumulative Pricing Rule')
|
||||
test_record = {
|
||||
@ -429,34 +429,61 @@ class TestPricingRule(unittest.TestCase):
|
||||
details = get_item_details(args)
|
||||
|
||||
self.assertTrue(details)
|
||||
|
||||
|
||||
def test_pricing_rule_for_condition(self):
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
|
||||
|
||||
|
||||
make_pricing_rule(selling=1, margin_type="Percentage", \
|
||||
condition="customer=='_Test Customer 1' and is_return==0", discount_percentage=10)
|
||||
|
||||
|
||||
# Incorrect Customer and Correct is_return value
|
||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 2", is_return=0)
|
||||
si.items[0].price_list_rate = 1000
|
||||
si.submit()
|
||||
item = si.items[0]
|
||||
self.assertEquals(item.rate, 100)
|
||||
|
||||
|
||||
# Correct Customer and Incorrect is_return value
|
||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=1, qty=-1)
|
||||
si.items[0].price_list_rate = 1000
|
||||
si.submit()
|
||||
item = si.items[0]
|
||||
self.assertEquals(item.rate, 100)
|
||||
|
||||
|
||||
# Correct Customer and correct is_return value
|
||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", is_return=0)
|
||||
si.items[0].price_list_rate = 1000
|
||||
si.submit()
|
||||
item = si.items[0]
|
||||
self.assertEquals(item.rate, 900)
|
||||
|
||||
|
||||
def test_multiple_pricing_rules(self):
|
||||
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
|
||||
title="_Test Pricing Rule 1")
|
||||
make_pricing_rule(discount_percentage=10, selling=1, title="_Test Pricing Rule 2", priority=2,
|
||||
apply_multiple_pricing_rules=1)
|
||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
|
||||
self.assertEqual(si.items[0].discount_percentage, 30)
|
||||
si.delete()
|
||||
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
|
||||
|
||||
def test_multiple_pricing_rules_with_apply_discount_on_discounted_rate(self):
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule")
|
||||
|
||||
make_pricing_rule(discount_percentage=20, selling=1, priority=1, apply_multiple_pricing_rules=1,
|
||||
title="_Test Pricing Rule 1")
|
||||
make_pricing_rule(discount_percentage=10, selling=1, priority=2,
|
||||
apply_discount_on_rate=1, title="_Test Pricing Rule 2", apply_multiple_pricing_rules=1)
|
||||
|
||||
si = create_sales_invoice(do_not_submit=True, customer="_Test Customer 1", qty=1)
|
||||
self.assertEqual(si.items[0].discount_percentage, 28)
|
||||
si.delete()
|
||||
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
|
||||
frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
|
||||
|
||||
def make_pricing_rule(**args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
@ -468,6 +495,7 @@ def make_pricing_rule(**args):
|
||||
"applicable_for": args.applicable_for,
|
||||
"selling": args.selling or 0,
|
||||
"currency": "USD",
|
||||
"apply_discount_on_rate": args.apply_discount_on_rate or 0,
|
||||
"buying": args.buying or 0,
|
||||
"min_qty": args.min_qty or 0.0,
|
||||
"max_qty": args.max_qty or 0.0,
|
||||
@ -476,9 +504,13 @@ def make_pricing_rule(**args):
|
||||
"rate": args.rate or 0.0,
|
||||
"margin_type": args.margin_type,
|
||||
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
||||
"condition": args.condition or ''
|
||||
"condition": args.condition or '',
|
||||
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
||||
})
|
||||
|
||||
if args.get("priority"):
|
||||
doc.priority = args.get("priority")
|
||||
|
||||
apply_on = doc.apply_on.replace(' ', '_').lower()
|
||||
child_table = {'Item Code': 'items', 'Item Group': 'item_groups', 'Brand': 'brands'}
|
||||
doc.append(child_table.get(doc.apply_on), {
|
||||
|
@ -14,9 +14,8 @@ import frappe
|
||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
from erpnext.stock.get_item_details import get_conversion_factor
|
||||
from frappe import _, throw
|
||||
from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
|
||||
|
||||
from frappe import _, bold
|
||||
from frappe.utils import cint, flt, get_link_to_form, getdate, today, fmt_money
|
||||
|
||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||
|
||||
@ -42,6 +41,7 @@ def get_pricing_rules(args, doc=None):
|
||||
if not pricing_rules: return []
|
||||
|
||||
if apply_multiple_pricing_rules(pricing_rules):
|
||||
pricing_rules = sorted_by_priority(pricing_rules)
|
||||
for pricing_rule in pricing_rules:
|
||||
pricing_rule = filter_pricing_rules(args, pricing_rule, doc)
|
||||
if pricing_rule:
|
||||
@ -53,6 +53,20 @@ def get_pricing_rules(args, doc=None):
|
||||
|
||||
return rules
|
||||
|
||||
def sorted_by_priority(pricing_rules):
|
||||
# If more than one pricing rules, then sort by priority
|
||||
pricing_rules_list = []
|
||||
pricing_rule_dict = {}
|
||||
for pricing_rule in pricing_rules:
|
||||
if not pricing_rule.get("priority"): continue
|
||||
|
||||
pricing_rule_dict.setdefault(cint(pricing_rule.get("priority")), []).append(pricing_rule)
|
||||
|
||||
for key in sorted(pricing_rule_dict):
|
||||
pricing_rules_list.append(pricing_rule_dict.get(key))
|
||||
|
||||
return pricing_rules_list or pricing_rules
|
||||
|
||||
def filter_pricing_rule_based_on_condition(pricing_rules, doc=None):
|
||||
filtered_pricing_rules = []
|
||||
if doc:
|
||||
@ -284,12 +298,13 @@ def validate_quantity_and_amount_for_suggestion(args, qty, amount, item_code, tr
|
||||
fieldname = field
|
||||
|
||||
if fieldname:
|
||||
msg = _("""If you {0} {1} quantities of the item <b>{2}</b>, the scheme <b>{3}</b>
|
||||
will be applied on the item.""").format(type_of_transaction, args.get(fieldname), item_code, args.rule_description)
|
||||
msg = (_("If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.")
|
||||
.format(type_of_transaction, args.get(fieldname), bold(item_code), bold(args.rule_description)))
|
||||
|
||||
if fieldname in ['min_amt', 'max_amt']:
|
||||
msg = _("""If you {0} {1} worth item <b>{2}</b>, the scheme <b>{3}</b> will be applied on the item.
|
||||
""").format(frappe.fmt_money(type_of_transaction, args.get(fieldname)), item_code, args.rule_description)
|
||||
msg = (_("If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.")
|
||||
.format(type_of_transaction, fmt_money(args.get(fieldname), currency=args.get("currency")),
|
||||
bold(item_code), bold(args.rule_description)))
|
||||
|
||||
frappe.msgprint(msg)
|
||||
|
||||
|
@ -237,7 +237,7 @@ class TestSubscription(unittest.TestCase):
|
||||
subscription.party_type = 'Customer'
|
||||
subscription.party = '_Test Customer'
|
||||
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
|
||||
subscription.start_date = '2018-01-01'
|
||||
subscription.start_date = add_days(nowdate(), -1000)
|
||||
subscription.insert()
|
||||
subscription.process() # generate first invoice
|
||||
|
||||
|
@ -63,6 +63,7 @@ def get_pos_entries(filters, group_by_field):
|
||||
FROM
|
||||
`tabPOS Invoice` p {from_sales_invoice_payment}
|
||||
WHERE
|
||||
p.docstatus = 1 and
|
||||
{group_by_mop_condition}
|
||||
{conditions}
|
||||
ORDER BY
|
||||
|
@ -9,9 +9,9 @@
|
||||
"filters_json": "{\"status\":\"In Location\",\"filter_based_on\":\"Fiscal Year\",\"period_start_date\":\"2020-04-01\",\"period_end_date\":\"2021-03-31\",\"date_based_on\":\"Purchase Date\",\"group_by\":\"--Select a group--\"}",
|
||||
"group_by_type": "Count",
|
||||
"idx": 0,
|
||||
"is_public": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-23 13:53:33.211371",
|
||||
"modified": "2020-10-28 23:15:58.432189",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Value Analytics",
|
||||
|
@ -8,9 +8,9 @@
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}",
|
||||
"filters_json": "{\"status\":\"In Location\",\"group_by\":\"Asset Category\",\"is_existing_asset\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-23 13:39:32.429240",
|
||||
"modified": "2020-10-28 23:16:16.939070",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Category-wise Asset Value",
|
||||
|
@ -8,9 +8,9 @@
|
||||
"dynamic_filters_json": "{\"company\":\"frappe.defaults.get_user_default(\\\"Company\\\")\",\"from_date\":\"frappe.datetime.add_months(frappe.datetime.nowdate(), -12)\",\"to_date\":\"frappe.datetime.nowdate()\"}",
|
||||
"filters_json": "{\"status\":\"In Location\",\"group_by\":\"Location\",\"is_existing_asset\":0}",
|
||||
"idx": 0,
|
||||
"is_public": 0,
|
||||
"is_public": 1,
|
||||
"is_standard": 1,
|
||||
"modified": "2020-07-23 13:42:44.912551",
|
||||
"modified": "2020-10-28 23:16:07.883312",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Location-wise Asset Value",
|
||||
|
@ -55,6 +55,7 @@
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Depreciation Posting Date",
|
||||
"mandatory_depends_on": "eval:parent.doctype == 'Asset'",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@ -86,7 +87,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-16 12:11:30.631788",
|
||||
"modified": "2020-10-30 15:22:29.119868",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Finance Book",
|
||||
|
@ -876,7 +876,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
},
|
||||
{
|
||||
"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 4","item_name":"_Test Item",
|
||||
"qty":250,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos", "name": po.supplied_items[1].name
|
||||
"qty":250,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"
|
||||
},
|
||||
]
|
||||
|
||||
@ -885,6 +885,10 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
|
||||
se.submit()
|
||||
|
||||
# Test po_detail field has value or not
|
||||
for item_row in se.items:
|
||||
self.assertEqual(item_row.po_detail, po.supplied_items[item_row.idx - 1].name)
|
||||
|
||||
po_doc = frappe.get_doc("Purchase Order", po.name)
|
||||
for row in po_doc.supplied_items:
|
||||
# Valid that whether transferred quantity is matching with supplied qty or not in the purchase order
|
||||
|
@ -304,7 +304,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
||||
{
|
||||
"fieldtype": "Select", "label": __("Get Suppliers By"),
|
||||
"fieldname": "search_type",
|
||||
"options": ["Tag","Supplier Group"],
|
||||
"options": ["Supplier Group", "Tag"],
|
||||
"reqd": 1,
|
||||
onchange() {
|
||||
if(dialog.get_value('search_type') == 'Tag'){
|
||||
|
@ -21,9 +21,9 @@
|
||||
"link_to_mrs",
|
||||
"supplier_response_section",
|
||||
"salutation",
|
||||
"email_template",
|
||||
"col_break_email_1",
|
||||
"subject",
|
||||
"col_break_email_1",
|
||||
"email_template",
|
||||
"preview",
|
||||
"sec_break_email_2",
|
||||
"message_for_supplier",
|
||||
@ -260,7 +260,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-16 17:49:09.561929",
|
||||
"modified": "2020-11-04 22:04:29.017134",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation",
|
||||
|
@ -5,14 +5,14 @@
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"send_email",
|
||||
"email_sent",
|
||||
"supplier",
|
||||
"contact",
|
||||
"quote_status",
|
||||
"column_break_3",
|
||||
"supplier_name",
|
||||
"email_id"
|
||||
"email_id",
|
||||
"send_email",
|
||||
"email_sent"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -87,7 +87,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-16 12:23:41.769820",
|
||||
"modified": "2020-11-04 22:01:43.832942",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Request for Quotation Supplier",
|
||||
|
@ -263,6 +263,7 @@ class AccountsController(TransactionBase):
|
||||
if self.doctype == "Quotation" and self.quotation_to == "Customer" and parent_dict.get("party_name"):
|
||||
parent_dict.update({"customer": parent_dict.get("party_name")})
|
||||
|
||||
self.pricing_rules = []
|
||||
for item in self.get("items"):
|
||||
if item.get("item_code"):
|
||||
args = parent_dict.copy()
|
||||
@ -301,6 +302,7 @@ class AccountsController(TransactionBase):
|
||||
|
||||
if ret.get("pricing_rules"):
|
||||
self.apply_pricing_rule_on_items(item, ret)
|
||||
self.set_pricing_rule_details(item, ret)
|
||||
|
||||
if self.doctype == "Purchase Invoice":
|
||||
self.set_expense_account(for_validate)
|
||||
@ -322,6 +324,9 @@ class AccountsController(TransactionBase):
|
||||
if item.get('discount_amount'):
|
||||
item.rate = item.price_list_rate - item.discount_amount
|
||||
|
||||
if item.get("apply_discount_on_discounted_rate") and pricing_rule_args.get("rate"):
|
||||
item.rate = pricing_rule_args.get("rate")
|
||||
|
||||
elif pricing_rule_args.get('free_item_data'):
|
||||
apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
|
||||
|
||||
@ -335,6 +340,18 @@ class AccountsController(TransactionBase):
|
||||
frappe.msgprint(_("Row {0}: user has not applied the rule {1} on the item {2}")
|
||||
.format(item.idx, frappe.bold(title), frappe.bold(item.item_code)))
|
||||
|
||||
def set_pricing_rule_details(self, item_row, args):
|
||||
pricing_rules = get_applied_pricing_rules(args.get("pricing_rules"))
|
||||
if not pricing_rules: return
|
||||
|
||||
for pricing_rule in pricing_rules:
|
||||
self.append("pricing_rules", {
|
||||
"pricing_rule": pricing_rule,
|
||||
"item_code": item_row.item_code,
|
||||
"child_docname": item_row.name,
|
||||
"rule_applied": True
|
||||
})
|
||||
|
||||
def set_taxes(self):
|
||||
if not self.meta.get_field("taxes"):
|
||||
return
|
||||
|
@ -301,7 +301,7 @@ class BuyingController(StockController):
|
||||
# backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
|
||||
|
||||
for raw_material in transferred_raw_materials + non_stock_items:
|
||||
rm_item_key = (raw_material.rm_item_code, item.purchase_order)
|
||||
rm_item_key = (raw_material.rm_item_code, item.item_code, item.purchase_order)
|
||||
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
|
||||
|
||||
consumed_qty = raw_material_data.get('qty', 0)
|
||||
@ -910,7 +910,7 @@ def get_backflushed_subcontracted_raw_materials(purchase_orders):
|
||||
purchase_receipt_supplied_items = get_supplied_items(args[1], args[2], references)
|
||||
|
||||
for data in purchase_receipt_supplied_items:
|
||||
pr_key = (data.rm_item_code, args[0])
|
||||
pr_key = (data.rm_item_code, data.main_item_code, args[0])
|
||||
if pr_key not in backflushed_raw_materials_map:
|
||||
backflushed_raw_materials_map.setdefault(pr_key, frappe._dict({
|
||||
"qty": 0.0,
|
||||
@ -936,7 +936,7 @@ def get_backflushed_subcontracted_raw_materials(purchase_orders):
|
||||
|
||||
def get_supplied_items(item_code, purchase_receipt, references):
|
||||
return frappe.get_all("Purchase Receipt Item Supplied",
|
||||
fields=["rm_item_code", "consumed_qty", "serial_no", "batch_no"],
|
||||
fields=["rm_item_code", "main_item_code", "consumed_qty", "serial_no", "batch_no"],
|
||||
filters={"main_item_code": item_code, "parent": purchase_receipt, "reference_name": ("in", references)})
|
||||
|
||||
def get_asset_item_details(asset_items):
|
||||
|
@ -608,16 +608,19 @@ class calculate_taxes_and_totals(object):
|
||||
base_rate_with_margin = 0.0
|
||||
if item.price_list_rate:
|
||||
if item.pricing_rules and not self.doc.ignore_pricing_rule:
|
||||
has_margin = False
|
||||
for d in get_applied_pricing_rules(item.pricing_rules):
|
||||
pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
|
||||
|
||||
if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\
|
||||
if (pricing_rule.margin_type in ['Amount', 'Percentage'] and pricing_rule.currency == self.doc.currency)\
|
||||
or (pricing_rule.margin_type == 'Percentage'):
|
||||
item.margin_type = pricing_rule.margin_type
|
||||
item.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
|
||||
else:
|
||||
item.margin_type = None
|
||||
item.margin_rate_or_amount = 0.0
|
||||
has_margin = True
|
||||
|
||||
if not has_margin:
|
||||
item.margin_type = None
|
||||
item.margin_rate_or_amount = 0.0
|
||||
|
||||
if item.margin_type and item.margin_rate_or_amount:
|
||||
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
|
||||
|
@ -75,6 +75,6 @@ class StudentAttendance(Document):
|
||||
})
|
||||
|
||||
if attendance_record:
|
||||
record = get_link_to_form('Attendance Record', attendance_record)
|
||||
record = get_link_to_form('Student Attendance', attendance_record)
|
||||
frappe.throw(_('Student Attendance record {0} already exists against the Student {1}')
|
||||
.format(record, frappe.bold(self.student)), title=_('Duplicate Entry'))
|
||||
|
@ -8,7 +8,7 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Payments",
|
||||
"links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }\n]"
|
||||
"links": "[\n {\n \"description\": \"GoCardless payment gateway settings\",\n \"label\": \"GoCardless Settings\",\n \"name\": \"GoCardless Settings\",\n \"type\": \"doctype\"\n }, {\n \"description\": \"M-Pesa payment gateway settings\",\n \"label\": \"M-Pesa Settings\",\n \"name\": \"Mpesa Settings\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
@ -29,7 +29,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "ERPNext Integrations",
|
||||
"modified": "2020-08-23 16:30:51.494655",
|
||||
"modified": "2020-10-29 19:54:46.228222",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "ERPNext Integrations",
|
||||
|
@ -9,11 +9,12 @@ frappe.ui.form.on('Mpesa Settings', {
|
||||
refresh: function(frm) {
|
||||
frappe.realtime.on("refresh_mpesa_dashboard", function(){
|
||||
frm.reload_doc();
|
||||
frm.events.setup_account_balance_html(frm);
|
||||
});
|
||||
},
|
||||
|
||||
get_account_balance: function(frm) {
|
||||
if (!frm.initiator_name && !frm.security_credentials) {
|
||||
if (!frm.doc.initiator_name && !frm.doc.security_credential) {
|
||||
frappe.throw(__("Please set the initiator name and the security credential"));
|
||||
}
|
||||
frappe.call({
|
||||
|
@ -147,7 +147,7 @@ def get_account_balance(request_payload):
|
||||
return response
|
||||
except Exception:
|
||||
frappe.log_error(title=_("Account Balance Processing Error"))
|
||||
frappe.throw(title=_("Error"), message=_("Please check your configuration and try again"))
|
||||
frappe.throw(_("Please check your configuration and try again"), title=_("Error"))
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def process_balance_info(**kwargs):
|
||||
@ -173,7 +173,8 @@ def process_balance_info(**kwargs):
|
||||
ref_doc.db_set("account_balance", balance_info)
|
||||
|
||||
request.handle_success(account_balance_response)
|
||||
frappe.publish_realtime("refresh_mpesa_dashboard")
|
||||
frappe.publish_realtime("refresh_mpesa_dashboard", doctype="Mpesa Settings",
|
||||
docname=transaction_data.reference_docname, user=transaction_data.owner)
|
||||
except Exception:
|
||||
request.handle_failure(account_balance_response)
|
||||
frappe.log_error(title=_("Mpesa Account Balance Processing Error"), message=account_balance_response)
|
||||
|
@ -31,6 +31,7 @@ class PlaidConnector():
|
||||
return access_token
|
||||
|
||||
def get_link_token(self):
|
||||
country_codes = ["US", "CA", "FR", "IE", "NL", "ES", "GB"] if self.settings.enable_european_access else ["US", "CA"]
|
||||
token_request = {
|
||||
"client_name": self.client_name,
|
||||
"client_id": self.settings.plaid_client_id,
|
||||
@ -38,7 +39,7 @@ class PlaidConnector():
|
||||
"products": self.products,
|
||||
# only allow Plaid-supported languages and countries (LAST: Sep-19-2020)
|
||||
"language": frappe.local.lang if frappe.local.lang in ["en", "fr", "es", "nl"] else "en",
|
||||
"country_codes": ["US", "CA", "FR", "IE", "NL", "ES", "GB"],
|
||||
"country_codes": country_codes,
|
||||
"user": {
|
||||
"client_user_id": frappe.generate_hash(frappe.session.user, length=32)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2018-10-25 10:02:48.656165",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@ -11,7 +12,8 @@
|
||||
"plaid_client_id",
|
||||
"plaid_secret",
|
||||
"column_break_7",
|
||||
"plaid_env"
|
||||
"plaid_env",
|
||||
"enable_european_access"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -58,10 +60,17 @@
|
||||
{
|
||||
"fieldname": "column_break_7",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enable_european_access",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable European Access"
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"modified": "2020-09-12 02:31:44.542385",
|
||||
"links": [],
|
||||
"modified": "2020-10-29 20:24:56.916104",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "Plaid Settings",
|
||||
|
@ -37,7 +37,8 @@
|
||||
"depends_on": "eval:doc.parenttype==\"Therapy\";",
|
||||
"fieldname": "counts_completed",
|
||||
"fieldtype": "Int",
|
||||
"label": "Counts Completed"
|
||||
"label": "Counts Completed",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "assistance_level",
|
||||
@ -48,7 +49,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-10 13:41:06.662351",
|
||||
"modified": "2020-11-04 18:20:25.583491",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Exercise",
|
||||
|
@ -21,6 +21,19 @@ frappe.ui.form.on('Inpatient Medication Entry', {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('warehouse', () => {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
patient: function(frm) {
|
||||
if (frm.doc.patient)
|
||||
frm.set_value('service_unit', '');
|
||||
},
|
||||
|
||||
get_medication_orders: function(frm) {
|
||||
|
@ -67,6 +67,7 @@
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval: doc.__islocal",
|
||||
"fieldname": "filters_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Filters"
|
||||
@ -93,6 +94,7 @@
|
||||
"options": "Patient"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.patient",
|
||||
"fieldname": "service_unit",
|
||||
"fieldtype": "Link",
|
||||
"label": "Healthcare Service Unit",
|
||||
@ -178,7 +180,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-30 23:40:45.528715",
|
||||
"modified": "2020-11-03 13:22:37.820707",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Inpatient Medication Entry",
|
||||
|
@ -199,6 +199,7 @@ class InpatientMedicationEntry(Document):
|
||||
|
||||
def get_pending_medication_orders(entry):
|
||||
filters, values = get_filters(entry)
|
||||
to_remove = []
|
||||
|
||||
data = frappe.db.sql("""
|
||||
SELECT
|
||||
@ -225,7 +226,10 @@ def get_pending_medication_orders(entry):
|
||||
doc['service_unit'] = get_current_healthcare_service_unit(inpatient_record)
|
||||
|
||||
if entry.service_unit and doc.service_unit != entry.service_unit:
|
||||
data.remove(doc)
|
||||
to_remove.append(doc)
|
||||
|
||||
for doc in to_remove:
|
||||
data.remove(doc)
|
||||
|
||||
return data
|
||||
|
||||
|
@ -12,7 +12,8 @@ frappe.ui.form.on('Inpatient Medication Order', {
|
||||
frm.set_query('patient', () => {
|
||||
return {
|
||||
filters: {
|
||||
'inpatient_record': ['!=', '']
|
||||
'inpatient_record': ['!=', ''],
|
||||
'inpatient_status': 'Admitted'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -13,43 +13,42 @@ frappe.ui.form.on('Therapy Plan', {
|
||||
refresh: function(frm) {
|
||||
if (!frm.doc.__islocal) {
|
||||
frm.trigger('show_progress_for_therapies');
|
||||
}
|
||||
|
||||
if (!frm.doc.__islocal && frm.doc.status != 'Completed') {
|
||||
let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type });
|
||||
const fields = [{
|
||||
fieldtype: 'Link',
|
||||
label: __('Therapy Type'),
|
||||
fieldname: 'therapy_type',
|
||||
options: 'Therapy Type',
|
||||
reqd: 1,
|
||||
get_query: function() {
|
||||
return {
|
||||
filters: { 'therapy_type': ['in', therapy_types]}
|
||||
if (frm.doc.status != 'Completed') {
|
||||
let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
|
||||
const fields = [{
|
||||
fieldtype: 'Link',
|
||||
label: __('Therapy Type'),
|
||||
fieldname: 'therapy_type',
|
||||
options: 'Therapy Type',
|
||||
reqd: 1,
|
||||
get_query: function() {
|
||||
return {
|
||||
filters: { 'therapy_type': ['in', therapy_types]}
|
||||
};
|
||||
}
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
frm.add_custom_button(__('Therapy Session'), function() {
|
||||
frappe.prompt(fields, data => {
|
||||
frappe.call({
|
||||
method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session',
|
||||
args: {
|
||||
therapy_plan: frm.doc.name,
|
||||
patient: frm.doc.patient,
|
||||
therapy_type: data.therapy_type,
|
||||
company: frm.doc.company
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
frappe.model.sync(r.message);
|
||||
frappe.set_route('Form', r.message.doctype, r.message.name);
|
||||
frm.add_custom_button(__('Therapy Session'), function() {
|
||||
frappe.prompt(fields, data => {
|
||||
frappe.call({
|
||||
method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session',
|
||||
args: {
|
||||
therapy_plan: frm.doc.name,
|
||||
patient: frm.doc.patient,
|
||||
therapy_type: data.therapy_type,
|
||||
company: frm.doc.company
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
frappe.model.sync(r.message);
|
||||
frappe.set_route('Form', r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, __('Select Therapy Type'), __('Create'));
|
||||
}, __('Create'));
|
||||
});
|
||||
}, __('Select Therapy Type'), __('Create'));
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if (frm.doc.therapy_plan_template && !frm.doc.invoiced) {
|
||||
frm.add_custom_button(__('Sales Invoice'), function() {
|
||||
|
@ -115,7 +115,8 @@
|
||||
"fieldname": "therapy_plan_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Therapy Plan Template",
|
||||
"options": "Therapy Plan Template"
|
||||
"options": "Therapy Plan Template",
|
||||
"set_only_once": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@ -128,7 +129,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-10-23 01:27:42.128855",
|
||||
"modified": "2020-11-04 18:13:13.564999",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Therapy Plan",
|
||||
|
@ -30,12 +30,13 @@
|
||||
"fieldname": "sessions_completed",
|
||||
"fieldtype": "Int",
|
||||
"label": "Sessions Completed",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-08 01:17:34.778028",
|
||||
"modified": "2020-11-04 18:15:52.173450",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Therapy Plan Detail",
|
||||
|
@ -22,6 +22,10 @@ frappe.ui.form.on('Therapy Session', {
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.therapy_plan) {
|
||||
frm.trigger('filter_therapy_types');
|
||||
}
|
||||
|
||||
if (!frm.doc.__islocal) {
|
||||
frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue');
|
||||
frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]),
|
||||
@ -36,15 +40,43 @@ frappe.ui.form.on('Therapy Session', {
|
||||
})
|
||||
}, 'Create');
|
||||
|
||||
frm.add_custom_button(__('Sales Invoice'), function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
|
||||
frm: frm,
|
||||
})
|
||||
}, 'Create');
|
||||
frappe.db.get_value('Therapy Plan', {'name': frm.doc.therapy_plan}, 'therapy_plan_template', (r) => {
|
||||
if (r && !r.therapy_plan_template) {
|
||||
frm.add_custom_button(__('Sales Invoice'), function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
|
||||
frm: frm,
|
||||
});
|
||||
}, 'Create');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
therapy_plan: function(frm) {
|
||||
if (frm.doc.therapy_plan) {
|
||||
frm.trigger('filter_therapy_types');
|
||||
}
|
||||
},
|
||||
|
||||
filter_therapy_types: function(frm) {
|
||||
frappe.call({
|
||||
'method': 'frappe.client.get',
|
||||
args: {
|
||||
doctype: 'Therapy Plan',
|
||||
name: frm.doc.therapy_plan
|
||||
},
|
||||
callback: function(data) {
|
||||
let therapy_types = (data.message.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
|
||||
frm.set_query('therapy_type', function() {
|
||||
return {
|
||||
filters: { 'therapy_type': ['in', therapy_types]}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
patient: function(frm) {
|
||||
if (frm.doc.patient) {
|
||||
frappe.call({
|
||||
@ -98,19 +130,6 @@ frappe.ui.form.on('Therapy Session', {
|
||||
frm.set_value(values);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let values = {
|
||||
'patient': '',
|
||||
'therapy_type': '',
|
||||
'therapy_plan': '',
|
||||
'practitioner': '',
|
||||
'department': '',
|
||||
'start_date': '',
|
||||
'start_time': '',
|
||||
'service_unit': '',
|
||||
'duration': ''
|
||||
};
|
||||
frm.set_value(values);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -194,6 +194,7 @@
|
||||
"fieldname": "total_counts_completed",
|
||||
"fieldtype": "Int",
|
||||
"label": "Total Counts Completed",
|
||||
"no_copy": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@ -222,7 +223,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-22 23:10:21.178644",
|
||||
"modified": "2020-11-04 18:14:25.999939",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Therapy Session",
|
||||
|
@ -56,23 +56,35 @@ frappe.ui.form.on('Production Plan', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 1) {
|
||||
frm.trigger("show_progress");
|
||||
|
||||
if (frm.doc.status !== "Completed") {
|
||||
if (frm.doc.po_items && frm.doc.status !== "Closed") {
|
||||
frm.add_custom_button(__("Work Order"), ()=> {
|
||||
frm.trigger("make_work_order");
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if (frm.doc.mr_items && !in_list(['Material Requested', 'Closed'], frm.doc.status)) {
|
||||
frm.add_custom_button(__("Material Request"), ()=> {
|
||||
frm.trigger("make_material_request");
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
if (frm.doc.status === "Closed") {
|
||||
frm.add_custom_button(__("Re-open"), function() {
|
||||
frm.events.close_open_production_plan(frm, false);
|
||||
}, __("Status"));
|
||||
} else {
|
||||
frm.add_custom_button(__("Close"), function() {
|
||||
frm.events.close_open_production_plan(frm, true);
|
||||
}, __("Status"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus === 1 && frm.doc.po_items
|
||||
&& frm.doc.status != 'Completed') {
|
||||
frm.add_custom_button(__("Work Order"), ()=> {
|
||||
frm.trigger("make_work_order");
|
||||
}, __('Create'));
|
||||
if (frm.doc.status !== "Closed") {
|
||||
frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus === 1 && frm.doc.mr_items
|
||||
&& !in_list(['Material Requested', 'Completed'], frm.doc.status)) {
|
||||
frm.add_custom_button(__("Material Request"), ()=> {
|
||||
frm.trigger("make_material_request");
|
||||
}, __('Create'));
|
||||
}
|
||||
|
||||
frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||
frm.trigger("material_requirement");
|
||||
|
||||
const projected_qty_formula = ` <table class="table table-bordered" style="background-color: #f9f9f9;">
|
||||
@ -121,6 +133,18 @@ frappe.ui.form.on('Production Plan', {
|
||||
set_field_options("projected_qty_formula", projected_qty_formula);
|
||||
},
|
||||
|
||||
close_open_production_plan: (frm, close=false) => {
|
||||
frappe.call({
|
||||
method: "set_status",
|
||||
freeze: true,
|
||||
doc: frm.doc,
|
||||
args: {close : close},
|
||||
callback: function() {
|
||||
frm.reload_doc();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_work_order: function(frm) {
|
||||
frappe.call({
|
||||
method: "make_work_order",
|
||||
|
@ -275,7 +275,7 @@
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested",
|
||||
"options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nClosed\nCancelled\nMaterial Requested",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@ -304,9 +304,10 @@
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-calendar",
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-02-03 00:25:25.934202",
|
||||
"modified": "2020-10-26 13:00:54.335319",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan",
|
||||
|
@ -219,13 +219,17 @@ class ProductionPlan(Document):
|
||||
filters = {'docstatus': 0, 'production_plan': ("=", self.name)}):
|
||||
frappe.delete_doc('Work Order', d.name)
|
||||
|
||||
def set_status(self):
|
||||
def set_status(self, close=None):
|
||||
self.status = {
|
||||
0: 'Draft',
|
||||
1: 'Submitted',
|
||||
2: 'Cancelled'
|
||||
}.get(self.docstatus)
|
||||
|
||||
if close:
|
||||
self.db_set('status', 'Closed')
|
||||
return
|
||||
|
||||
if self.total_produced_qty > 0:
|
||||
self.status = "In Process"
|
||||
if self.total_produced_qty == self.total_planned_qty:
|
||||
@ -235,6 +239,9 @@ class ProductionPlan(Document):
|
||||
self.update_ordered_status()
|
||||
self.update_requested_status()
|
||||
|
||||
if close is not None:
|
||||
self.db_set('status', self.status)
|
||||
|
||||
def update_ordered_status(self):
|
||||
update_status = False
|
||||
for d in self.po_items:
|
||||
@ -735,10 +742,12 @@ def get_items_for_material_requests(doc, warehouses=None):
|
||||
mr_items = new_mr_items
|
||||
|
||||
if not mr_items:
|
||||
frappe.msgprint(_("""As raw materials projected quantity is more than required quantity,
|
||||
there is no need to create material request for the warehouse {0}.
|
||||
Still if you want to make material request,
|
||||
kindly enable <b>Ignore Existing Projected Quantity</b> checkbox""").format(doc.get('for_warehouse')))
|
||||
to_enable = frappe.bold(_("Ignore Existing Projected Quantity"))
|
||||
warehouse = frappe.bold(doc.get('for_warehouse'))
|
||||
message = _("As there are sufficient raw materials, Material Request is not required for Warehouse {0}.").format(warehouse) + "<br><br>"
|
||||
message += _(" If you still want to proceed, please enable {0}.").format(to_enable)
|
||||
|
||||
frappe.msgprint(message, title=_("Note"))
|
||||
|
||||
return mr_items
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
frappe.listview_settings['Production Plan'] = {
|
||||
add_fields: ["status"],
|
||||
filters: [["status", "!=", "Stopped"]],
|
||||
filters: [["status", "!=", "Closed"]],
|
||||
get_indicator: function(doc) {
|
||||
if(doc.status==="Submitted") {
|
||||
return [__("Not Started"), "orange", "status,=,Submitted"];
|
||||
@ -10,7 +10,8 @@ frappe.listview_settings['Production Plan'] = {
|
||||
"In Process": "orange",
|
||||
"Completed": "green",
|
||||
"Material Requested": "darkgrey",
|
||||
"Cancelled": "darkgrey"
|
||||
"Cancelled": "darkgrey",
|
||||
"Closed": "grey"
|
||||
}[doc.status], "status,=," + doc.status];
|
||||
}
|
||||
}
|
||||
|
@ -11,30 +11,20 @@
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Warehouse",
|
||||
"options": "Warehouse"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-02-02 10:37:16.650836",
|
||||
"modified": "2020-10-26 12:55:00.778201",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan Material Request Warehouse",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
@ -2,7 +2,15 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Routing', {
|
||||
setup: function(frm) {
|
||||
refresh: function(frm) {
|
||||
frm.trigger("display_sequence_id_column");
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
frm.trigger("display_sequence_id_column");
|
||||
},
|
||||
|
||||
display_sequence_id_column: function(frm) {
|
||||
frappe.meta.get_docfield("BOM Operation", "sequence_id",
|
||||
frm.doc.name).in_list_view = true;
|
||||
|
||||
|
@ -732,3 +732,5 @@ erpnext.patches.v13_0.set_youtube_video_id
|
||||
erpnext.patches.v13_0.print_uom_after_quantity_patch
|
||||
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
|
||||
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
|
||||
erpnext.patches.v13_0.update_reason_for_resignation_in_employee
|
||||
execute:frappe.delete_doc("Report", "Quoted Item Comparison")
|
@ -53,7 +53,7 @@ def execute():
|
||||
# renamed reports from "Minutes to First Response for Issues" to "First Response Time for Issues". Same for Opportunity
|
||||
for report in ['Minutes to First Response for Issues', 'Minutes to First Response for Opportunity']:
|
||||
if frappe.db.exists('Report', report):
|
||||
frappe.delete_doc('Report', report)
|
||||
frappe.delete_doc('Report', report, ignore_permissions=True)
|
||||
|
||||
|
||||
def convert_to_seconds(value, unit):
|
||||
|
@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("hr", "doctype", "employee")
|
||||
|
||||
if frappe.db.has_column("Employee", "reason_for_resignation"):
|
||||
frappe.db.sql(""" UPDATE `tabEmployee`
|
||||
SET reason_for_leaving = reason_for_resignation
|
||||
WHERE status = 'Left' and reason_for_leaving is null and reason_for_resignation is not null
|
||||
""")
|
||||
|
@ -352,9 +352,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
let show_description = function(idx, exist = null) {
|
||||
if (exist) {
|
||||
scan_barcode_field.set_new_description(__('Row #{0}: Qty increased by 1', [idx]));
|
||||
frappe.show_alert({
|
||||
message: __('Row #{0}: Qty increased by 1', [idx]),
|
||||
indicator: 'green'
|
||||
});
|
||||
} else {
|
||||
scan_barcode_field.set_new_description(__('Row #{0}: Item added', [idx]));
|
||||
frappe.show_alert({
|
||||
message: __('Row #{0}: Item added', [idx]),
|
||||
indicator: 'green'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,7 +371,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}).then(r => {
|
||||
const data = r && r.message;
|
||||
if (!data || Object.keys(data).length === 0) {
|
||||
scan_barcode_field.set_new_description(__('Cannot find Item with this barcode'));
|
||||
frappe.show_alert({
|
||||
message: __('Cannot find Item with this Barcode'),
|
||||
indicator: 'red'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -651,7 +660,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
let child = frappe.model.add_child(me.frm.doc, "taxes");
|
||||
child.charge_type = "On Net Total";
|
||||
child.account_head = tax;
|
||||
child.rate = rate;
|
||||
child.rate = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Review and Action",
|
||||
"links": "[\n {\n \"description\": \"Quality Review\",\n \"label\": \"Quality Review\",\n \"name\": \"Quality Review\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Action\",\n \"label\": \"Quality Action\",\n \"name\": \"Quality Action\",\n \"type\": \"doctype\"\n }\n]"
|
||||
"links": "[\n {\n \"description\": \"Non Conformance\",\n \"label\": \"Non Conformance\",\n \"name\": \"Non Conformance\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Review\",\n \"label\": \"Quality Review\",\n \"name\": \"Quality Review\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Quality Action\",\n \"label\": \"Quality Action\",\n \"name\": \"Quality Action\",\n \"type\": \"doctype\"\n }\n]"
|
||||
}
|
||||
],
|
||||
"category": "Modules",
|
||||
@ -29,11 +29,11 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "Desk Page",
|
||||
"extends_another_page": 0,
|
||||
"icon": "",
|
||||
"hide_custom": 0,
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Quality",
|
||||
"modified": "2020-04-01 11:28:51.095012",
|
||||
"modified": "2020-10-27 16:28:54.138055",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality",
|
||||
@ -47,6 +47,7 @@
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"doc_view": "Tree",
|
||||
"label": "Quality Procedure",
|
||||
"link_to": "Quality Procedure",
|
||||
"type": "DocType"
|
||||
@ -55,6 +56,33 @@
|
||||
"label": "Quality Inspection",
|
||||
"link_to": "Quality Inspection",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"color": "#ff8989",
|
||||
"doc_view": "",
|
||||
"format": "{} Open",
|
||||
"label": "Quality Review",
|
||||
"link_to": "Quality Review",
|
||||
"stats_filter": "{\"status\": \"Open\"}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"color": "#ff8989",
|
||||
"doc_view": "",
|
||||
"format": "{} Open",
|
||||
"label": "Quality Action",
|
||||
"link_to": "Quality Action",
|
||||
"stats_filter": "{\"status\": \"Open\"}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"color": "#ff8989",
|
||||
"doc_view": "",
|
||||
"format": "{} Open",
|
||||
"label": "Non Conformance",
|
||||
"link_to": "Non Conformance",
|
||||
"stats_filter": "{\"status\": \"Open\"}",
|
||||
"type": "DocType"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Non Conformance', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -0,0 +1,118 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:QA-NC-{#####}",
|
||||
"creation": "2020-10-21 14:49:50.350136",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"subject",
|
||||
"procedure",
|
||||
"process_owner",
|
||||
"full_name",
|
||||
"column_break_4",
|
||||
"status",
|
||||
"section_break_4",
|
||||
"details",
|
||||
"corrective_action",
|
||||
"preventive_action"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "subject",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Subject",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "procedure",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Procedure",
|
||||
"options": "Quality Procedure",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Open\nResolved\nCancelled",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "details",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Details"
|
||||
},
|
||||
{
|
||||
"fetch_from": "procedure.process_owner",
|
||||
"fieldname": "process_owner",
|
||||
"fieldtype": "Data",
|
||||
"label": "Process Owner",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "process_owner.full_name",
|
||||
"fieldname": "full_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Full Name"
|
||||
},
|
||||
{
|
||||
"fieldname": "corrective_action",
|
||||
"fieldtype": "Text",
|
||||
"label": "Corrective Action"
|
||||
},
|
||||
{
|
||||
"fieldname": "preventive_action",
|
||||
"fieldtype": "Text",
|
||||
"label": "Preventive Action"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-26 15:27:47.247814",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Non Conformance",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class NonConformance(Document):
|
||||
pass
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestNonConformance(unittest.TestCase):
|
||||
pass
|
@ -2,32 +2,5 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Action', {
|
||||
onload: function(frm) {
|
||||
frm.set_value("date", frappe.datetime.get_today());
|
||||
frm.refresh();
|
||||
},
|
||||
document_name: function(frm){
|
||||
frappe.call({
|
||||
"method": "frappe.client.get",
|
||||
args: {
|
||||
doctype: frm.doc.document_type,
|
||||
name: frm.doc.document_name
|
||||
},
|
||||
callback: function(data){
|
||||
frm.fields_dict.resolutions.grid.remove_all();
|
||||
let objectives = [];
|
||||
|
||||
if(frm.doc.document_type === "Quality Review"){
|
||||
for(let i in data.message.reviews) objectives.push(data.message.reviews[i].review);
|
||||
} else {
|
||||
for(let j in data.message.parameters) objectives.push(data.message.parameters[j].feedback);
|
||||
}
|
||||
for (var objective in objectives){
|
||||
frm.add_child("resolutions");
|
||||
frm.fields_dict.resolutions.get_value()[objective].problem = objectives[objective];
|
||||
}
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
@ -1,32 +1,34 @@
|
||||
{
|
||||
"autoname": "format:ACTN-{#####}",
|
||||
"actions": [],
|
||||
"autoname": "format:QA-ACT-{#####}",
|
||||
"creation": "2018-10-02 11:40:43.666100",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"corrective_preventive",
|
||||
"document_type",
|
||||
"goal",
|
||||
"review",
|
||||
"feedback",
|
||||
"status",
|
||||
"cb_00",
|
||||
"date",
|
||||
"document_name",
|
||||
"goal",
|
||||
"procedure",
|
||||
"status",
|
||||
"sb_00",
|
||||
"resolutions"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"depends_on": "eval:doc.type == 'Quality Review'",
|
||||
"fetch_from": "review.goal",
|
||||
"fieldname": "goal",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Goal",
|
||||
"options": "Quality Goal",
|
||||
"read_only": 1
|
||||
"options": "Quality Goal"
|
||||
},
|
||||
{
|
||||
"default": "Today",
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
@ -34,34 +36,20 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.type == 'Quality Review'",
|
||||
"fieldname": "procedure",
|
||||
"fieldtype": "Link",
|
||||
"label": "Procedure",
|
||||
"options": "Quality Procedure",
|
||||
"read_only": 1
|
||||
"options": "Quality Procedure"
|
||||
},
|
||||
{
|
||||
"default": "Open",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"options": "Open\nClosed"
|
||||
},
|
||||
{
|
||||
"fieldname": "document_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Document Name",
|
||||
"options": "document_type"
|
||||
},
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Document Type",
|
||||
"options": "Quality Review\nQuality Feedback",
|
||||
"reqd": 1
|
||||
"options": "Open\nCompleted",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "Corrective",
|
||||
@ -86,9 +74,24 @@
|
||||
"fieldtype": "Table",
|
||||
"label": "Resolutions",
|
||||
"options": "Quality Action Resolution"
|
||||
},
|
||||
{
|
||||
"fieldname": "review",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Review",
|
||||
"options": "Quality Review"
|
||||
},
|
||||
{
|
||||
"fieldname": "feedback",
|
||||
"fieldtype": "Link",
|
||||
"label": "Feedback",
|
||||
"options": "Quality Feedback"
|
||||
}
|
||||
],
|
||||
"modified": "2019-05-28 13:10:44.092497",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-27 16:21:59.533937",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Action",
|
||||
|
@ -7,4 +7,5 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class QualityAction(Document):
|
||||
pass
|
||||
def validate(self):
|
||||
self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Quality Action", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Quality Actions
|
||||
() => frappe.tests.make('Quality Actions', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -5,42 +5,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
|
||||
from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_unit
|
||||
from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_goal
|
||||
from erpnext.quality_management.doctype.quality_review.test_quality_review import create_review
|
||||
|
||||
class TestQualityAction(unittest.TestCase):
|
||||
|
||||
def test_quality_action(self):
|
||||
create_procedure()
|
||||
create_unit()
|
||||
create_goal()
|
||||
create_review()
|
||||
test_create_action = create_action()
|
||||
test_get_action = get_action()
|
||||
|
||||
self.assertEquals(test_create_action, test_get_action)
|
||||
|
||||
def create_action():
|
||||
review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
|
||||
action = frappe.get_doc({
|
||||
"doctype": "Quality Action",
|
||||
"action": "Corrective",
|
||||
"document_type": "Quality Review",
|
||||
"document_name": review,
|
||||
"date": frappe.utils.nowdate(),
|
||||
"goal": "GOAL-_Test Quality Goal",
|
||||
"procedure": "PRC-_Test Quality Procedure"
|
||||
})
|
||||
action_exist = frappe.db.exists("Quality Action", {"review": review})
|
||||
|
||||
if not action_exist:
|
||||
action.insert()
|
||||
return action.name
|
||||
else:
|
||||
return action_exist
|
||||
|
||||
def get_action():
|
||||
review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
|
||||
return frappe.db.exists("Quality Action", {"document_name": review})
|
||||
# quality action has no code
|
||||
pass
|
@ -1,33 +1,54 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-05-26 20:36:44.337186",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"problem",
|
||||
"sb_00",
|
||||
"resolution"
|
||||
"resolution",
|
||||
"status",
|
||||
"responsible",
|
||||
"completion_by"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "problem",
|
||||
"fieldtype": "Long Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Review"
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_00",
|
||||
"fieldtype": "Section Break"
|
||||
"label": "Problem"
|
||||
},
|
||||
{
|
||||
"fieldname": "resolution",
|
||||
"fieldtype": "Text Editor",
|
||||
"in_list_view": 1,
|
||||
"label": "Resolution"
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Open\nCompleted"
|
||||
},
|
||||
{
|
||||
"fieldname": "responsible",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Responsible",
|
||||
"options": "User"
|
||||
},
|
||||
{
|
||||
"fieldname": "completion_by",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Completion By"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-05-28 13:09:50.435323",
|
||||
"links": [],
|
||||
"modified": "2020-10-21 12:59:25.566682",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Action Resolution",
|
||||
|
@ -2,31 +2,9 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Feedback', {
|
||||
refresh: function(frm) {
|
||||
frm.set_value("date", frappe.datetime.get_today());
|
||||
},
|
||||
|
||||
template: function(frm) {
|
||||
if (frm.doc.template) {
|
||||
frappe.call({
|
||||
"method": "frappe.client.get",
|
||||
args: {
|
||||
doctype: "Quality Feedback Template",
|
||||
name: frm.doc.template
|
||||
},
|
||||
callback: function(data) {
|
||||
if (data && data.message) {
|
||||
frm.fields_dict.parameters.grid.remove_all();
|
||||
|
||||
// fetch parameters from template and autofill
|
||||
for (let template_parameter of data.message.parameters) {
|
||||
let row = frm.add_child("parameters");
|
||||
row.parameter = template_parameter.parameter;
|
||||
}
|
||||
frm.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
frm.call('set_parameters');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,16 +1,15 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:FDBK-{#####}",
|
||||
"autoname": "format:QA-FB-{#####}",
|
||||
"creation": "2019-05-26 21:23:05.308379",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"document_type",
|
||||
"template",
|
||||
"cb_00",
|
||||
"document_type",
|
||||
"document_name",
|
||||
"date",
|
||||
"sb_00",
|
||||
"parameters"
|
||||
],
|
||||
@ -18,6 +17,7 @@
|
||||
{
|
||||
"fieldname": "template",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Template",
|
||||
"options": "Quality Feedback Template",
|
||||
"reqd": 1
|
||||
@ -26,13 +26,6 @@
|
||||
"fieldname": "cb_00",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_00",
|
||||
"fieldtype": "Section Break"
|
||||
@ -47,6 +40,7 @@
|
||||
{
|
||||
"fieldname": "document_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Type",
|
||||
"options": "User\nCustomer",
|
||||
"reqd": 1
|
||||
@ -54,13 +48,20 @@
|
||||
{
|
||||
"fieldname": "document_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Feedback By",
|
||||
"options": "document_type",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-07-03 15:50:58.589302",
|
||||
"links": [
|
||||
{
|
||||
"group": "Actions",
|
||||
"link_doctype": "Quality Action",
|
||||
"link_fieldname": "feedback"
|
||||
}
|
||||
],
|
||||
"modified": "2020-10-27 16:20:10.918544",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Feedback",
|
||||
|
@ -7,4 +7,17 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class QualityFeedback(Document):
|
||||
pass
|
||||
def set_parameters(self):
|
||||
if self.template and not getattr(self, 'parameters', []):
|
||||
for d in frappe.get_doc('Quality Feedback Template', self.template).parameters:
|
||||
self.append('parameters', dict(
|
||||
parameter = d.parameter,
|
||||
rating = 1
|
||||
))
|
||||
|
||||
def validate(self):
|
||||
if not self.document_name:
|
||||
self.document_type ='User'
|
||||
self.document_name = frappe.session.user
|
||||
self.set_parameters()
|
||||
|
||||
|
@ -5,49 +5,27 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.quality_management.doctype.quality_feedback_template.test_quality_feedback_template import create_template
|
||||
|
||||
|
||||
class TestQualityFeedback(unittest.TestCase):
|
||||
|
||||
def test_quality_feedback(self):
|
||||
create_template()
|
||||
test_create_feedback = create_feedback()
|
||||
test_get_feedback = get_feedback()
|
||||
template = frappe.get_doc(dict(
|
||||
doctype = 'Quality Feedback Template',
|
||||
template = 'Test Template',
|
||||
parameters = [
|
||||
dict(parameter='Test Parameter 1'),
|
||||
dict(parameter='Test Parameter 2')
|
||||
]
|
||||
)).insert()
|
||||
|
||||
self.assertEqual(test_create_feedback, test_get_feedback)
|
||||
feedback = frappe.get_doc(dict(
|
||||
doctype = 'Quality Feedback',
|
||||
template = template.name,
|
||||
document_type = 'User',
|
||||
document_name = frappe.session.user
|
||||
)).insert()
|
||||
|
||||
def create_feedback():
|
||||
create_customer()
|
||||
self.assertEqual(template.parameters[0].parameter, feedback.parameters[0].parameter)
|
||||
|
||||
feedabck = frappe.get_doc({
|
||||
"doctype": "Quality Feedback",
|
||||
"template": "TMPL-_Test Feedback Template",
|
||||
"document_type": "Customer",
|
||||
"document_name": "Quality Feedback Customer",
|
||||
"date": frappe.utils.nowdate(),
|
||||
"parameters": [
|
||||
{
|
||||
"parameter": "Test Parameter",
|
||||
"rating": 3,
|
||||
"feedback": "Test Feedback"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
feedback_exists = frappe.db.exists("Quality Feedback", {"template": "TMPL-_Test Feedback Template"})
|
||||
|
||||
if not feedback_exists:
|
||||
feedabck.insert()
|
||||
return feedabck.name
|
||||
else:
|
||||
return feedback_exists
|
||||
|
||||
def get_feedback():
|
||||
return frappe.db.exists("Quality Feedback", {"template": "TMPL-_Test Feedback Template"})
|
||||
|
||||
def create_customer():
|
||||
if not frappe.db.exists("Customer", {"customer_name": "Quality Feedback Customer"}):
|
||||
customer = frappe.get_doc({
|
||||
"doctype": "Customer",
|
||||
"customer_name": "Quality Feedback Customer"
|
||||
}).insert(ignore_permissions=True)
|
||||
feedback.delete()
|
||||
template.delete()
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-05-26 21:25:01.715807",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@ -39,12 +40,13 @@
|
||||
"fieldname": "feedback",
|
||||
"fieldtype": "Text Editor",
|
||||
"in_list_view": 1,
|
||||
"label": "Feedback",
|
||||
"reqd": 1
|
||||
"label": "Feedback"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-07-13 19:58:08.966141",
|
||||
"links": [],
|
||||
"modified": "2020-10-27 17:28:12.033145",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Feedback Parameter",
|
||||
|
@ -1,13 +1,12 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:TMPL-{template}",
|
||||
"autoname": "field:template",
|
||||
"creation": "2019-05-26 21:17:24.283061",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"template",
|
||||
"cb_00",
|
||||
"sb_00",
|
||||
"parameters"
|
||||
],
|
||||
@ -16,12 +15,9 @@
|
||||
"fieldname": "template",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Template",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cb_00",
|
||||
"fieldtype": "Column Break"
|
||||
"label": "Template Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_00",
|
||||
@ -35,8 +31,14 @@
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-07-03 16:06:03.749415",
|
||||
"links": [
|
||||
{
|
||||
"group": "Records",
|
||||
"link_doctype": "Quality Feedback",
|
||||
"link_fieldname": "template"
|
||||
}
|
||||
],
|
||||
"modified": "2020-10-27 16:18:53.579688",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Feedback Template",
|
||||
|
@ -7,31 +7,4 @@ import frappe
|
||||
import unittest
|
||||
|
||||
class TestQualityFeedbackTemplate(unittest.TestCase):
|
||||
|
||||
def test_quality_feedback_template(self):
|
||||
test_create_template = create_template()
|
||||
test_get_template = get_template()
|
||||
|
||||
self.assertEqual(test_create_template, test_get_template)
|
||||
|
||||
def create_template():
|
||||
template = frappe.get_doc({
|
||||
"doctype": "Quality Feedback Template",
|
||||
"template": "_Test Feedback Template",
|
||||
"parameters": [
|
||||
{
|
||||
"parameter": "Test Parameter"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
template_exists = frappe.db.exists("Quality Feedback Template", {"template": "_Test Feedback Template"})
|
||||
|
||||
if not template_exists:
|
||||
template.insert()
|
||||
return template.name
|
||||
else:
|
||||
return template_exists
|
||||
|
||||
def get_template():
|
||||
return frappe.db.exists("Quality Feedback Template", {"template": "_Test Feedback Template"})
|
||||
pass
|
@ -2,7 +2,6 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Goal', {
|
||||
refresh: function(frm) {
|
||||
frm.doc.created_by = frappe.session.user;
|
||||
}
|
||||
// refresh: function(frm) {
|
||||
// }
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"autoname": "format:GOAL-{goal}",
|
||||
"actions": [],
|
||||
"autoname": "field:goal",
|
||||
"creation": "2018-10-02 12:17:41.727541",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@ -7,27 +8,14 @@
|
||||
"field_order": [
|
||||
"goal",
|
||||
"frequency",
|
||||
"created_by",
|
||||
"cb_00",
|
||||
"procedure",
|
||||
"weekday",
|
||||
"quarter",
|
||||
"date",
|
||||
"sb_00",
|
||||
"revision",
|
||||
"cb_01",
|
||||
"revised_on",
|
||||
"sb_01",
|
||||
"objectives"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "created_by",
|
||||
"fieldtype": "Link",
|
||||
"label": "Created By",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "None",
|
||||
"fieldname": "frequency",
|
||||
@ -50,20 +38,6 @@
|
||||
"label": "Date",
|
||||
"options": "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "revision",
|
||||
"fieldtype": "Int",
|
||||
"label": "Revision",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "revised_on",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Revised On",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.frequency == 'Weekly';",
|
||||
"fieldname": "weekday",
|
||||
@ -75,15 +49,6 @@
|
||||
"fieldname": "cb_00",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_00",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Revision and Revised On"
|
||||
},
|
||||
{
|
||||
"fieldname": "cb_01",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_01",
|
||||
"fieldtype": "Section Break",
|
||||
@ -101,18 +66,17 @@
|
||||
"label": "Goal",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"default": "January-April-July-October",
|
||||
"depends_on": "eval:doc.frequency == 'Quarterly';",
|
||||
"fieldname": "quarter",
|
||||
"fieldtype": "Select",
|
||||
"label": "Quarter",
|
||||
"options": "January-April-July-October",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"modified": "2019-05-28 14:49:12.768863",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Review",
|
||||
"link_doctype": "Quality Review",
|
||||
"link_fieldname": "goal"
|
||||
}
|
||||
],
|
||||
"modified": "2020-10-27 15:57:59.368605",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Goal",
|
||||
|
@ -8,7 +8,5 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class QualityGoal(Document):
|
||||
|
||||
def validate(self):
|
||||
self.revision += 1
|
||||
self.revised_on = frappe.utils.today()
|
||||
pass
|
@ -1,12 +0,0 @@
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'goal',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Review'),
|
||||
'items': ['Quality Review']
|
||||
}
|
||||
]
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Quality Goal", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Quality Goal
|
||||
() => frappe.tests.make('Quality Goal', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -8,44 +8,18 @@ import unittest
|
||||
from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
|
||||
|
||||
class TestQualityGoal(unittest.TestCase):
|
||||
|
||||
def test_quality_goal(self):
|
||||
create_procedure()
|
||||
create_unit()
|
||||
test_create_goal = create_goal()
|
||||
test_get_goal = get_goal()
|
||||
# no code, just a basic sanity check
|
||||
goal = get_quality_goal()
|
||||
self.assertTrue(goal)
|
||||
goal.delete()
|
||||
|
||||
self.assertEquals(test_create_goal, test_get_goal)
|
||||
|
||||
def create_goal():
|
||||
goal = frappe.get_doc({
|
||||
"doctype": "Quality Goal",
|
||||
"goal": "_Test Quality Goal",
|
||||
"procedure": "PRC-_Test Quality Procedure",
|
||||
"objectives": [
|
||||
{
|
||||
"objective": "_Test Quality Objective",
|
||||
"target": "4",
|
||||
"uom": "_Test UOM"
|
||||
}
|
||||
def get_quality_goal():
|
||||
return frappe.get_doc(dict(
|
||||
doctype = 'Quality Goal',
|
||||
goal = 'Test Quality Module',
|
||||
frequency = 'Daily',
|
||||
objectives = [
|
||||
dict(objective = 'Check test cases', target='100', uom='Percent')
|
||||
]
|
||||
})
|
||||
goal_exist = frappe.db.exists("Quality Goal", {"goal": goal.goal})
|
||||
if not goal_exist:
|
||||
goal.insert()
|
||||
return goal.name
|
||||
else:
|
||||
return goal_exist
|
||||
|
||||
def get_goal():
|
||||
goal = frappe.db.exists("Quality Goal", "GOAL-_Test Quality Goal")
|
||||
return goal
|
||||
|
||||
def create_unit():
|
||||
unit = frappe.get_doc({
|
||||
"doctype": "UOM",
|
||||
"uom_name": "_Test UOM",
|
||||
})
|
||||
unit_exist = frappe.db.exists("UOM", unit.uom_name)
|
||||
if not unit_exist:
|
||||
unit.insert()
|
||||
)).insert()
|
@ -2,8 +2,5 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Meeting', {
|
||||
onload: function(frm){
|
||||
frm.set_value("date", frappe.datetime.get_today());
|
||||
frm.refresh();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -1,28 +1,19 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "naming_series:",
|
||||
"autoname": "format:QA-MEET-{YY}-{MM}-{DD}",
|
||||
"creation": "2018-10-15 16:25:41.548432",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"naming_series",
|
||||
"date",
|
||||
"cb_00",
|
||||
"status",
|
||||
"cb_00",
|
||||
"sb_00",
|
||||
"agenda",
|
||||
"sb_01",
|
||||
"minutes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "Open",
|
||||
"fieldname": "status",
|
||||
@ -55,16 +46,11 @@
|
||||
"fieldname": "sb_01",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Minutes"
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Naming Series",
|
||||
"options": "MTNG-.YYYY.-.MM.-.DD.-"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-19 13:18:59.821740",
|
||||
"modified": "2020-10-27 16:36:45.657883",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Meeting",
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Quality Meeting", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Quality Meeting
|
||||
() => frappe.tests.make('Quality Meeting', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -5,41 +5,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.quality_management.doctype.quality_review.test_quality_review import create_review
|
||||
|
||||
class TestQualityMeeting(unittest.TestCase):
|
||||
def test_quality_meeting(self):
|
||||
create_review()
|
||||
test_create_meeting = create_meeting()
|
||||
test_get_meeting = get_meeting()
|
||||
self.assertEquals(test_create_meeting, test_get_meeting)
|
||||
|
||||
def create_meeting():
|
||||
meeting = frappe.get_doc({
|
||||
"doctype": "Quality Meeting",
|
||||
"status": "Open",
|
||||
"date": frappe.utils.nowdate(),
|
||||
"agenda": [
|
||||
{
|
||||
"agenda": "Test Agenda"
|
||||
}
|
||||
],
|
||||
"minutes": [
|
||||
{
|
||||
"document_type": "Quality Review",
|
||||
"document_name": frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"}),
|
||||
"minute": "Test Minute"
|
||||
}
|
||||
]
|
||||
})
|
||||
meeting_exist = frappe.db.exists("Quality Meeting", {"date": frappe.utils.nowdate(), "status": "Open"})
|
||||
|
||||
if not meeting_exist:
|
||||
meeting.insert()
|
||||
return meeting.name
|
||||
else:
|
||||
return meeting_exist
|
||||
|
||||
def get_meeting():
|
||||
meeting = frappe.db.exists("Quality Meeting", {"date": frappe.utils.nowdate(), "status": "Open"})
|
||||
return meeting
|
||||
# nothing to test
|
||||
pass
|
@ -1,19 +1,22 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "format:PRC-{quality_procedure_name}",
|
||||
"autoname": "field:quality_procedure_name",
|
||||
"creation": "2018-10-06 00:06:29.756804",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"quality_procedure_name",
|
||||
"process_owner",
|
||||
"process_owner_full_name",
|
||||
"section_break_3",
|
||||
"processes",
|
||||
"sb_00",
|
||||
"parent_quality_procedure",
|
||||
"is_group",
|
||||
"sb_00",
|
||||
"processes",
|
||||
"lft",
|
||||
"rgt",
|
||||
"lft",
|
||||
"old_parent"
|
||||
],
|
||||
"fields": [
|
||||
@ -34,14 +37,14 @@
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "Lft",
|
||||
"label": "Left Index",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "Rgt",
|
||||
"label": "Right Index",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@ -54,7 +57,7 @@
|
||||
{
|
||||
"fieldname": "sb_00",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Processes"
|
||||
"label": "Parent"
|
||||
},
|
||||
{
|
||||
"fieldname": "processes",
|
||||
@ -67,12 +70,52 @@
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Quality Procedure",
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "process_owner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Process Owner",
|
||||
"options": "User"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fetch_from": "process_owner.full_name",
|
||||
"fieldname": "process_owner_full_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Process Owner Full Name",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-13 11:46:07.744194",
|
||||
"links": [
|
||||
{
|
||||
"group": "Reviews",
|
||||
"link_doctype": "Quality Review",
|
||||
"link_fieldname": "procedure"
|
||||
},
|
||||
{
|
||||
"group": "Goals",
|
||||
"link_doctype": "Quality Goal",
|
||||
"link_fieldname": "procedure"
|
||||
},
|
||||
{
|
||||
"group": "Actions",
|
||||
"link_doctype": "Quality Action",
|
||||
"link_fieldname": "procedure"
|
||||
},
|
||||
{
|
||||
"group": "Actions",
|
||||
"link_doctype": "Non Conformance",
|
||||
"link_fieldname": "procedure"
|
||||
}
|
||||
],
|
||||
"modified": "2020-10-26 15:25:39.316088",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Procedure",
|
||||
|
@ -14,69 +14,58 @@ class QualityProcedure(NestedSet):
|
||||
self.check_for_incorrect_child()
|
||||
|
||||
def on_update(self):
|
||||
NestedSet.on_update(self)
|
||||
self.set_parent()
|
||||
|
||||
def after_insert(self):
|
||||
self.set_parent()
|
||||
#if Child is Added through Tree View.
|
||||
|
||||
# add child to parent if missing
|
||||
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()
|
||||
parent = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
|
||||
if not [d for d in parent.processes if d.procedure == self.name]:
|
||||
parent.append("processes", {"procedure": self.name, "process_description": self.name})
|
||||
parent.save()
|
||||
|
||||
def on_trash(self):
|
||||
if self.parent_quality_procedure:
|
||||
doc = frappe.get_doc("Quality Procedure", self.parent_quality_procedure)
|
||||
for process in doc.processes:
|
||||
if process.procedure == self.name:
|
||||
doc.processes.remove(process)
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
flag_is_group = 0
|
||||
doc.load_from_db()
|
||||
|
||||
for process in doc.processes:
|
||||
flag_is_group = 1 if process.procedure else 0
|
||||
|
||||
doc.is_group = 0 if flag_is_group == 0 else 1
|
||||
doc.save(ignore_permissions=True)
|
||||
# clear from child table (sub procedures)
|
||||
frappe.db.sql('''update `tabQuality Procedure Process`
|
||||
set `procedure`='' where `procedure`=%s''', self.name)
|
||||
NestedSet.on_trash(self, allow_root_deletion=True)
|
||||
|
||||
def set_parent(self):
|
||||
rebuild_tree('Quality Procedure', 'parent_quality_procedure')
|
||||
|
||||
for process in self.processes:
|
||||
# Set parent for only those children who don't have a parent
|
||||
parent_quality_procedure = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
|
||||
if not parent_quality_procedure and process.procedure:
|
||||
has_parent = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
|
||||
if not has_parent and process.procedure:
|
||||
frappe.db.set_value(self.doctype, process.procedure, "parent_quality_procedure", self.name)
|
||||
|
||||
def check_for_incorrect_child(self):
|
||||
for process in self.processes:
|
||||
if process.procedure:
|
||||
self.is_group = 1
|
||||
# Check if any child process belongs to another parent.
|
||||
parent_quality_procedure = frappe.db.get_value("Quality Procedure", process.procedure, "parent_quality_procedure")
|
||||
if parent_quality_procedure and parent_quality_procedure != self.name:
|
||||
frappe.throw(_("{0} already has a Parent Procedure {1}.".format(frappe.bold(process.procedure), frappe.bold(parent_quality_procedure))),
|
||||
frappe.throw(_("{0} already has a Parent Procedure {1}.").format(frappe.bold(process.procedure), frappe.bold(parent_quality_procedure)),
|
||||
title=_("Invalid Child Procedure"))
|
||||
self.is_group = 1
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_children(doctype, parent=None, parent_quality_procedure=None, is_root=False):
|
||||
if parent is None or parent == "All Quality Procedures":
|
||||
parent = ""
|
||||
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
name as value,
|
||||
is_group as expandable
|
||||
from
|
||||
`tab{doctype}`
|
||||
where
|
||||
ifnull(parent_quality_procedure, "")={parent}
|
||||
""".format(
|
||||
doctype = doctype,
|
||||
parent=frappe.db.escape(parent)
|
||||
), as_dict=1)
|
||||
if parent:
|
||||
parent_procedure = frappe.get_doc('Quality Procedure', parent)
|
||||
# return the list in order
|
||||
return [dict(
|
||||
value=d.procedure,
|
||||
expandable=frappe.db.get_value('Quality Procedure', d.procedure, 'is_group'))
|
||||
for d in parent_procedure.processes if d.procedure
|
||||
]
|
||||
else:
|
||||
return frappe.get_all(doctype, fields=['name as value', 'is_group as expandable'],
|
||||
filters = dict(parent_quality_procedure = parent), order_by='name asc')
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_node():
|
||||
@ -88,4 +77,4 @@ def add_node():
|
||||
if args.parent_quality_procedure == 'All Quality Procedures':
|
||||
args.parent_quality_procedure = None
|
||||
|
||||
frappe.get_doc(args).insert()
|
||||
return frappe.get_doc(args).insert()
|
@ -1,20 +0,0 @@
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'procedure',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Goal'),
|
||||
'items': ['Quality Goal']
|
||||
},
|
||||
{
|
||||
'label': _('Review'),
|
||||
'items': ['Quality Review']
|
||||
},
|
||||
{
|
||||
'label': _('Action'),
|
||||
'items': ['Quality Action']
|
||||
}
|
||||
],
|
||||
}
|
@ -15,7 +15,7 @@ frappe.treeview_settings["Quality Procedure"] = {
|
||||
}
|
||||
},
|
||||
],
|
||||
breadcrumb: "Setup",
|
||||
breadcrumb: "Quality Management",
|
||||
disable_add_node: true,
|
||||
root_label: "All Quality Procedures",
|
||||
get_tree_root: false,
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Quality Procedure", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Quality Procedure
|
||||
() => frappe.tests.make('Quality Procedure', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -6,54 +6,45 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestQualityProcedure(unittest.TestCase):
|
||||
def test_quality_procedure(self):
|
||||
test_create_procedure = create_procedure()
|
||||
test_create_nested_procedure = create_nested_procedure()
|
||||
test_get_procedure, test_get_nested_procedure = get_procedure()
|
||||
from .quality_procedure import add_node
|
||||
|
||||
self.assertEquals(test_create_procedure, test_get_procedure.get("name"))
|
||||
self.assertEquals(test_create_nested_procedure, test_get_nested_procedure.get("name"))
|
||||
class TestQualityProcedure(unittest.TestCase):
|
||||
def test_add_node(self):
|
||||
try:
|
||||
procedure = frappe.get_doc(dict(
|
||||
doctype = 'Quality Procedure',
|
||||
quality_procedure_name = 'Test Procedure 1',
|
||||
processes = [
|
||||
dict(process_description = 'Test Step 1')
|
||||
]
|
||||
)).insert()
|
||||
|
||||
frappe.form_dict = dict(doctype = 'Quality Procedure', quality_procedure_name = 'Test Child 1',
|
||||
parent_quality_procedure = procedure.name, cmd='test', is_root='false')
|
||||
node = add_node()
|
||||
|
||||
procedure.reload()
|
||||
|
||||
self.assertEqual(procedure.is_group, 1)
|
||||
|
||||
# child row created
|
||||
self.assertTrue([d for d in procedure.processes if d.procedure == node.name])
|
||||
|
||||
node.delete()
|
||||
procedure.reload()
|
||||
|
||||
# child unset
|
||||
self.assertFalse([d for d in procedure.processes if d.name == node.name])
|
||||
|
||||
finally:
|
||||
procedure.delete()
|
||||
|
||||
def create_procedure():
|
||||
procedure = frappe.get_doc({
|
||||
"doctype": "Quality Procedure",
|
||||
"quality_procedure_name": "_Test Quality Procedure",
|
||||
"processes": [
|
||||
{
|
||||
"process_description": "_Test Quality Procedure Table",
|
||||
}
|
||||
return frappe.get_doc(dict(
|
||||
doctype = 'Quality Procedure',
|
||||
quality_procedure_name = 'Test Procedure 1',
|
||||
is_group = 1,
|
||||
processes = [
|
||||
dict(process_description = 'Test Step 1')
|
||||
]
|
||||
})
|
||||
|
||||
procedure_exist = frappe.db.exists("Quality Procedure", "PRC-_Test Quality Procedure")
|
||||
|
||||
if not procedure_exist:
|
||||
procedure.insert()
|
||||
return procedure.name
|
||||
else:
|
||||
return procedure_exist
|
||||
|
||||
def create_nested_procedure():
|
||||
nested_procedure = frappe.get_doc({
|
||||
"doctype": "Quality Procedure",
|
||||
"quality_procedure_name": "_Test Nested Quality Procedure",
|
||||
"processes": [
|
||||
{
|
||||
"procedure": "PRC-_Test Quality Procedure"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
nested_procedure_exist = frappe.db.exists("Quality Procedure", "PRC-_Test Nested Quality Procedure")
|
||||
|
||||
if not nested_procedure_exist:
|
||||
nested_procedure.insert()
|
||||
return nested_procedure.name
|
||||
else:
|
||||
return nested_procedure_exist
|
||||
|
||||
def get_procedure():
|
||||
procedure = frappe.get_doc("Quality Procedure", "PRC-_Test Quality Procedure")
|
||||
nested_procedure = frappe.get_doc("Quality Procedure", "PRC-_Test Nested Quality Procedure")
|
||||
return {"name": procedure.name}, {"name": nested_procedure.name, "parent_quality_procedure": nested_procedure.parent_quality_procedure}
|
||||
)).insert()
|
@ -10,6 +10,7 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 8,
|
||||
"fieldname": "process_description",
|
||||
"fieldtype": "Text Editor",
|
||||
"in_list_view": 1,
|
||||
@ -20,13 +21,14 @@
|
||||
"fieldname": "procedure",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Child Procedure",
|
||||
"label": "Sub Procedure",
|
||||
"options": "Quality Procedure"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-06-17 15:44:38.937915",
|
||||
"modified": "2020-10-27 13:55:11.252945",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Procedure Process",
|
||||
|
@ -2,9 +2,6 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Quality Review', {
|
||||
onload: function(frm){
|
||||
frm.set_value("date", frappe.datetime.get_today());
|
||||
},
|
||||
goal: function(frm) {
|
||||
frappe.call({
|
||||
"method": "frappe.client.get",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:REV-{#####}",
|
||||
"autoname": "format:QA-REV-{#####}",
|
||||
"creation": "2018-10-02 11:45:16.301955",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@ -18,6 +18,7 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "Today",
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
@ -50,7 +51,7 @@
|
||||
"collapsible": 1,
|
||||
"fieldname": "sb_01",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Additional Information"
|
||||
"label": "Notes"
|
||||
},
|
||||
{
|
||||
"fieldname": "reviews",
|
||||
@ -63,7 +64,8 @@
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Open\nClosed"
|
||||
"options": "Open\nPassed\nFailed",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "goal",
|
||||
@ -74,8 +76,15 @@
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-02-01 10:59:38.933115",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Review",
|
||||
"link_doctype": "Quality Action",
|
||||
"link_fieldname": "review"
|
||||
}
|
||||
],
|
||||
"modified": "2020-10-21 12:56:47.046172",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Review",
|
||||
@ -120,5 +129,6 @@
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "goal",
|
||||
"track_changes": 1
|
||||
}
|
@ -7,7 +7,26 @@ import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class QualityReview(Document):
|
||||
pass
|
||||
def validate(self):
|
||||
# fetch targets from goal
|
||||
if not self.reviews:
|
||||
for d in frappe.get_doc('Quality Goal', self.goal).objectives:
|
||||
self.append('reviews', dict(
|
||||
objective = d.objective,
|
||||
target = d.target,
|
||||
uom = d.uom
|
||||
))
|
||||
|
||||
self.set_status()
|
||||
|
||||
def set_status(self):
|
||||
# if any child item is failed, fail the parent
|
||||
if not len(self.reviews or []) or any([d.status=='Open' for d in self.reviews]):
|
||||
self.status = 'Open'
|
||||
elif any([d.status=='Failed' for d in self.reviews]):
|
||||
self.status = 'Failed'
|
||||
else:
|
||||
self.status = 'Passed'
|
||||
|
||||
def review():
|
||||
day = frappe.utils.getdate().day
|
||||
@ -24,7 +43,7 @@ def review():
|
||||
elif goal.frequency == 'Monthly' and goal.date == str(day):
|
||||
create_review(goal.name)
|
||||
|
||||
elif goal.frequency == 'Quarterly' and goal.data == str(day) and get_quarter(month):
|
||||
elif goal.frequency == 'Quarterly' and day==1 and get_quarter(month):
|
||||
create_review(goal.name)
|
||||
|
||||
def create_review(goal):
|
||||
@ -36,15 +55,6 @@ def create_review(goal):
|
||||
"date": frappe.utils.getdate()
|
||||
})
|
||||
|
||||
for objective in goal.objectives:
|
||||
review.append("reviews",
|
||||
{
|
||||
"objective": objective.objective,
|
||||
"target": objective.target,
|
||||
"uom": objective.uom
|
||||
}
|
||||
)
|
||||
|
||||
review.insert(ignore_permissions=True)
|
||||
|
||||
def get_quarter(month):
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Performance Monitoring", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Performance Monitoring
|
||||
() => frappe.tests.make('Performance Monitoring', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -5,42 +5,18 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
|
||||
from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_unit
|
||||
from erpnext.quality_management.doctype.quality_goal.test_quality_goal import create_goal
|
||||
|
||||
from ..quality_goal.test_quality_goal import get_quality_goal
|
||||
from .quality_review import review
|
||||
|
||||
class TestQualityReview(unittest.TestCase):
|
||||
def test_review_creation(self):
|
||||
quality_goal = get_quality_goal()
|
||||
review()
|
||||
|
||||
def test_quality_review(self):
|
||||
create_procedure()
|
||||
create_unit()
|
||||
create_goal()
|
||||
test_create_review = create_review()
|
||||
test_get_review = get_review()
|
||||
self.assertEquals(test_create_review, test_get_review)
|
||||
# check if review exists
|
||||
quality_review = frappe.get_doc('Quality Review', dict(goal = quality_goal.name))
|
||||
self.assertEqual(quality_goal.objectives[0].target, quality_review.reviews[0].target)
|
||||
quality_review.delete()
|
||||
|
||||
def create_review():
|
||||
review = frappe.get_doc({
|
||||
"doctype": "Quality Review",
|
||||
"goal": "GOAL-_Test Quality Goal",
|
||||
"procedure": "PRC-_Test Quality Procedure",
|
||||
"date": frappe.utils.nowdate(),
|
||||
"reviews": [
|
||||
{
|
||||
"objective": "_Test Quality Objective",
|
||||
"target": "100",
|
||||
"uom": "_Test UOM",
|
||||
"review": "Test Review"
|
||||
}
|
||||
]
|
||||
})
|
||||
review_exist = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
|
||||
if not review_exist:
|
||||
review.insert(ignore_permissions=True)
|
||||
return review.name
|
||||
else:
|
||||
return review_exist
|
||||
|
||||
def get_review():
|
||||
review = frappe.db.exists("Quality Review", {"goal": "GOAL-_Test Quality Goal"})
|
||||
return review
|
||||
quality_goal.delete()
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-05-26 15:17:44.796958",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@ -9,10 +10,12 @@
|
||||
"target",
|
||||
"uom",
|
||||
"sb_00",
|
||||
"status",
|
||||
"review"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 3,
|
||||
"fieldname": "objective",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
@ -20,6 +23,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "target",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
@ -27,6 +31,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"columns": 1,
|
||||
"fetch_from": "target_unit",
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
@ -49,10 +54,20 @@
|
||||
{
|
||||
"fieldname": "cb_00",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Open\nPassed\nFailed"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-05-26 16:14:12.586128",
|
||||
"links": [],
|
||||
"modified": "2020-10-27 16:28:20.908637",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Quality Management",
|
||||
"name": "Quality Review Objective",
|
||||
|
@ -139,7 +139,7 @@ def get_place_of_supply(party_details, doctype):
|
||||
if not frappe.get_meta('Address').has_field('gst_state'): return
|
||||
|
||||
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
|
||||
address_name = party_details.shipping_address_name or party_details.customer_address
|
||||
address_name = party_details.customer_address or party_details.shipping_address_name
|
||||
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
|
||||
address_name = party_details.shipping_address or party_details.supplier_address
|
||||
|
||||
|
@ -14,11 +14,9 @@ from six import string_types
|
||||
def get_items(start, page_length, price_list, item_group, pos_profile, search_value=""):
|
||||
data = dict()
|
||||
result = []
|
||||
warehouse, show_only_available_items = "", False
|
||||
|
||||
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
|
||||
if not allow_negative_stock:
|
||||
warehouse, show_only_available_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'show_only_available_items'])
|
||||
warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items'])
|
||||
|
||||
if not frappe.db.exists('Item Group', item_group):
|
||||
item_group = get_root_of('Item Group')
|
||||
@ -48,7 +46,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va
|
||||
lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt'])
|
||||
|
||||
bin_join_selection, bin_join_condition = "", ""
|
||||
if show_only_available_items:
|
||||
if hide_unavailable_items:
|
||||
bin_join_selection = ", `tabBin` bin"
|
||||
bin_join_condition = "AND bin.warehouse = %(warehouse)s AND bin.item_code = item.name AND bin.actual_qty > 0"
|
||||
|
||||
@ -97,7 +95,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_va
|
||||
for item in items_data:
|
||||
item_code = item.item_code
|
||||
item_price = item_prices.get(item_code) or {}
|
||||
if not allow_negative_stock:
|
||||
if allow_negative_stock:
|
||||
item_stock_qty = frappe.db.sql("""select ifnull(sum(actual_qty), 0) from `tabBin` where item_code = %s""", item_code)[0][0]
|
||||
else:
|
||||
item_stock_qty = get_stock_availability(item_code, warehouse)
|
||||
@ -231,13 +229,31 @@ def set_customer_info(fieldname, customer, value=""):
|
||||
frappe.db.set_value('Customer', customer, 'loyalty_program', value)
|
||||
|
||||
contact = frappe.get_cached_value('Customer', customer, 'customer_primary_contact')
|
||||
if not contact:
|
||||
contact = frappe.db.sql("""
|
||||
SELECT parent FROM `tabDynamic Link`
|
||||
WHERE
|
||||
parenttype = 'Contact' AND
|
||||
parentfield = 'links' AND
|
||||
link_doctype = 'Customer' AND
|
||||
link_name = %s
|
||||
""", (customer), as_dict=1)
|
||||
contact = contact[0].get('parent') if contact else None
|
||||
|
||||
if contact:
|
||||
contact_doc = frappe.get_doc('Contact', contact)
|
||||
if fieldname == 'email_id':
|
||||
contact_doc.set('email_ids', [{ 'email_id': value, 'is_primary': 1}])
|
||||
frappe.db.set_value('Customer', customer, 'email_id', value)
|
||||
elif fieldname == 'mobile_no':
|
||||
contact_doc.set('phone_nos', [{ 'phone': value, 'is_primary_mobile_no': 1}])
|
||||
frappe.db.set_value('Customer', customer, 'mobile_no', value)
|
||||
contact_doc.save()
|
||||
if not contact:
|
||||
new_contact = frappe.new_doc('Contact')
|
||||
new_contact.is_primary_contact = 1
|
||||
new_contact.first_name = customer
|
||||
new_contact.set('links', [{'link_doctype': 'Customer', 'link_name': customer}])
|
||||
new_contact.save()
|
||||
contact = new_contact.name
|
||||
frappe.db.set_value('Customer', customer, 'customer_primary_contact', contact)
|
||||
|
||||
contact_doc = frappe.get_doc('Contact', contact)
|
||||
if fieldname == 'email_id':
|
||||
contact_doc.set('email_ids', [{ 'email_id': value, 'is_primary': 1}])
|
||||
frappe.db.set_value('Customer', customer, 'email_id', value)
|
||||
elif fieldname == 'mobile_no':
|
||||
contact_doc.set('phone_nos', [{ 'phone': value, 'is_primary_mobile_no': 1}])
|
||||
frappe.db.set_value('Customer', customer, 'mobile_no', value)
|
||||
contact_doc.save()
|
@ -637,7 +637,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
if (!(available_qty > 0)) {
|
||||
frappe.model.clear_doc(item_row.doctype, item_row.name);
|
||||
frappe.throw({
|
||||
title: _("Not Available"),
|
||||
title: __("Not Available"),
|
||||
message: __('Item Code: {0} is not available under warehouse {1}.', [bold_item_code, bold_warehouse])
|
||||
})
|
||||
} else if (available_qty < qty_needed) {
|
||||
|
@ -81,7 +81,7 @@ erpnext.PointOfSale.ItemSelector = class {
|
||||
function get_item_image_html() {
|
||||
if (item_image) {
|
||||
return `<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
|
||||
<img class="h-full" src="${item_image}" alt="${item_image}" style="object-fit: cover;">
|
||||
<img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
|
||||
</div>`
|
||||
} else {
|
||||
return `<div class="flex items-center justify-center h-32 bg-light-grey text-6xl text-grey-100">
|
||||
|
@ -409,7 +409,7 @@ erpnext.PointOfSale.Payment = class {
|
||||
${
|
||||
shortcuts.map(s => {
|
||||
return `<div class="shortcut rounded bg-light-grey text-dark-grey pt-2 pb-2 no-select pointer" data-value="${s}">
|
||||
${format_currency(s, currency)}
|
||||
${format_currency(s, currency, 0)}
|
||||
</div>`
|
||||
}).join('')
|
||||
}
|
||||
|
@ -236,7 +236,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-12 16:11:31.910508",
|
||||
"modified": "2020-10-21 13:03:11.938072",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Quality Inspection",
|
||||
@ -257,7 +257,6 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"search_fields": "item_code, report_date, reference_name",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
|
@ -615,6 +615,15 @@ class StockEntry(StockController):
|
||||
if not row.subcontracted_item:
|
||||
frappe.throw(_("Row {0}: Subcontracted Item is mandatory for the raw material {1}")
|
||||
.format(row.idx, frappe.bold(row.item_code)))
|
||||
elif not row.po_detail:
|
||||
filters = {
|
||||
"parent": self.purchase_order, "docstatus": 1,
|
||||
"rm_item_code": row.item_code, "main_item_code": row.subcontracted_item
|
||||
}
|
||||
|
||||
po_detail = frappe.db.get_value("Purchase Order Item Supplied", filters, "name")
|
||||
if po_detail:
|
||||
row.db_set("po_detail", po_detail)
|
||||
|
||||
def validate_bom(self):
|
||||
for d in self.get('items'):
|
||||
|
@ -168,6 +168,7 @@ def get_stock_ledger_entries(filters, items):
|
||||
from
|
||||
`tabStock Ledger Entry` sle force index (posting_sort_index)
|
||||
where sle.docstatus < 2 %s %s
|
||||
and is_cancelled = 0
|
||||
order by sle.posting_date, sle.posting_time, sle.creation, sle.actual_qty""" % #nosec
|
||||
(item_conditions_sql, conditions), as_dict=1)
|
||||
|
||||
|
@ -288,7 +288,6 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
||||
return
|
||||
|
||||
convertible_cols = {}
|
||||
|
||||
is_dict_obj = False
|
||||
if isinstance(result[0], dict):
|
||||
is_dict_obj = True
|
||||
@ -310,13 +309,13 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
||||
for row_idx, row in enumerate(result):
|
||||
data = row.items() if is_dict_obj else enumerate(row)
|
||||
for key, value in data:
|
||||
if not key in convertible_columns or not conversion_factors[row_idx]:
|
||||
if key not in convertible_columns or not conversion_factors[row_idx-1]:
|
||||
continue
|
||||
|
||||
if convertible_columns.get(key) == 'rate':
|
||||
new_value = flt(value) * conversion_factors[row_idx]
|
||||
new_value = flt(value) * conversion_factors[row_idx-1]
|
||||
else:
|
||||
new_value = flt(value) / conversion_factors[row_idx]
|
||||
new_value = flt(value) / conversion_factors[row_idx-1]
|
||||
|
||||
if not is_dict_obj:
|
||||
row.insert(key+1, new_value)
|
||||
|
@ -7,7 +7,7 @@ import json
|
||||
from frappe import _
|
||||
from frappe import utils
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import time_diff_in_hours, now_datetime, getdate, get_weekdays, add_to_date, today, get_time, get_datetime, time_diff_in_seconds, time_diff
|
||||
from frappe.utils import now_datetime, getdate, get_weekdays, add_to_date, get_time, get_datetime, time_diff_in_seconds
|
||||
from datetime import datetime, timedelta
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe.utils.user import is_website_user
|
||||
@ -355,13 +355,13 @@ def set_service_level_agreement_variance(issue=None):
|
||||
doc = frappe.get_doc("Issue", issue.name)
|
||||
|
||||
if not doc.first_responded_on: # first_responded_on set when first reply is sent to customer
|
||||
variance = round(time_diff_in_hours(doc.response_by, current_time), 2)
|
||||
variance = round(time_diff_in_seconds(doc.response_by, current_time), 2)
|
||||
frappe.db.set_value(dt="Issue", dn=doc.name, field="response_by_variance", val=variance, update_modified=False)
|
||||
if variance < 0:
|
||||
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
|
||||
|
||||
if not doc.resolution_date: # resolution_date set when issue has been closed
|
||||
variance = round(time_diff_in_hours(doc.resolution_by, current_time), 2)
|
||||
variance = round(time_diff_in_seconds(doc.resolution_by, current_time), 2)
|
||||
frappe.db.set_value(dt="Issue", dn=doc.name, field="resolution_by_variance", val=variance, update_modified=False)
|
||||
if variance < 0:
|
||||
frappe.db.set_value(dt="Issue", dn=doc.name, field="agreement_status", val="Failed", update_modified=False)
|
||||
|
@ -473,7 +473,6 @@ Cannot deduct when category is for 'Valuation' or 'Valuation and Total',Kan nie
|
||||
Cannot deduct when category is for 'Valuation' or 'Vaulation and Total',Kan nie aftrek as die kategorie vir 'Waardasie' of 'Vaulering en Totaal' is nie.,
|
||||
"Cannot delete Serial No {0}, as it is used in stock transactions","Kan nie reeksnommer {0} uitvee nie, aangesien dit in voorraadtransaksies gebruik word",
|
||||
Cannot enroll more than {0} students for this student group.,Kan nie meer as {0} studente vir hierdie studente groep inskryf nie.,
|
||||
Cannot find Item with this barcode,Kan geen item met hierdie strepieskode vind nie,
|
||||
Cannot find active Leave Period,Kan nie aktiewe verlofperiode vind nie,
|
||||
Cannot produce more Item {0} than Sales Order quantity {1},Kan nie meer item {0} produseer as hoeveelheid van die bestelling {1},
|
||||
Cannot promote Employee with status Left,Kan nie werknemer bevorder met status links nie,
|
||||
@ -690,7 +689,6 @@ Create Variants,Skep variante,
|
||||
"Create and manage daily, weekly and monthly email digests.","Skep en bestuur daaglikse, weeklikse en maandelikse e-posverdelings.",
|
||||
Create customer quotes,Skep kliënte kwotasies,
|
||||
Create rules to restrict transactions based on values.,Skep reëls om transaksies gebaseer op waardes te beperk.,
|
||||
Created By,Gemaak deur,
|
||||
Created {0} scorecards for {1} between: ,Geskep {0} telkaarte vir {1} tussen:,
|
||||
Creating Company and Importing Chart of Accounts,Skep 'n maatskappy en voer rekeningrekeninge in,
|
||||
Creating Fees,Fooie skep,
|
||||
@ -1078,7 +1076,6 @@ For Warehouse is required before Submit,Vir die pakhuis word vereis voor indieni
|
||||
For row {0}: Enter Planned Qty,Vir ry {0}: Gee beplande hoeveelheid,
|
||||
"For {0}, only credit accounts can be linked against another debit entry",Vir {0} kan slegs kredietrekeninge gekoppel word teen 'n ander debietinskrywing,
|
||||
"For {0}, only debit accounts can be linked against another credit entry",Vir {0} kan slegs debietrekeninge gekoppel word teen 'n ander kredietinskrywing,
|
||||
Form View,Form View,
|
||||
Forum Activity,Forum Aktiwiteit,
|
||||
Free item code is not selected,Gratis itemkode word nie gekies nie,
|
||||
Freight and Forwarding Charges,Vrag en vragkoste,
|
||||
@ -2638,7 +2635,6 @@ Send SMS,Stuur SMS,
|
||||
Send mass SMS to your contacts,Stuur massa-SMS na jou kontakte,
|
||||
Sensitivity,sensitiwiteit,
|
||||
Sent,gestuur,
|
||||
Serial #,Serie #,
|
||||
Serial No and Batch,Serial No and Batch,
|
||||
Serial No is mandatory for Item {0},Volgnummer is verpligtend vir item {0},
|
||||
Serial No {0} does not belong to Batch {1},Reeksnommer {0} hoort nie by bondel {1},
|
||||
@ -3303,7 +3299,6 @@ Welcome to ERPNext,Welkom by ERPNext,
|
||||
What do you need help with?,Waarmee het jy hulp nodig?,
|
||||
What does it do?,Wat doen dit?,
|
||||
Where manufacturing operations are carried.,Waar vervaardigingsbedrywighede uitgevoer word.,
|
||||
"While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Terwyl u rekening vir kindermaatskappy {0} skep, word ouerrekening {1} nie gevind nie. Skep asseblief die ouerrekening in die ooreenstemmende COA",
|
||||
White,wit,
|
||||
Wire Transfer,Elektroniese oorbetaling,
|
||||
WooCommerce Products,WooCommerce Produkte,
|
||||
@ -3493,6 +3488,7 @@ Likes,Hou,
|
||||
Merge with existing,Voeg saam met bestaande,
|
||||
Office,kantoor,
|
||||
Orientation,geaardheid,
|
||||
Parent,Ouer,
|
||||
Passive,passiewe,
|
||||
Payment Failed,Betaling misluk,
|
||||
Percent,persent,
|
||||
@ -3543,6 +3539,7 @@ Shift,verskuiwing,
|
||||
Show {0},Wys {0},
|
||||
"Special Characters except ""-"", ""#"", ""."", ""/"", ""{"" and ""}"" not allowed in naming series","Spesiale karakters behalwe "-", "#", ".", "/", "{" En "}" word nie toegelaat in die naamreekse nie",
|
||||
Target Details,Teikenbesonderhede,
|
||||
{0} already has a Parent Procedure {1}.,{0} het reeds 'n ouerprosedure {1}.,
|
||||
API,API,
|
||||
Annual,jaarlikse,
|
||||
Approved,goedgekeur,
|
||||
@ -7558,10 +7555,6 @@ Quality Feedback Template Parameter,Parameter vir gehalte-terugvoersjabloon,
|
||||
Quality Goal,Kwaliteit doel,
|
||||
Monitoring Frequency,Monitor frekwensie,
|
||||
Weekday,weekdag,
|
||||
January-April-July-October,Januarie-April-Julie-Oktober,
|
||||
Revision and Revised On,Hersiening en hersien op,
|
||||
Revision,hersiening,
|
||||
Revised On,Hersien op,
|
||||
Objectives,doelwitte,
|
||||
Quality Goal Objective,Kwaliteit Doelwit,
|
||||
Objective,Doel,
|
||||
@ -7574,7 +7567,6 @@ Parent Procedure,Ouerprosedure,
|
||||
Processes,prosesse,
|
||||
Quality Procedure Process,Kwaliteit prosedure proses,
|
||||
Process Description,Prosesbeskrywing,
|
||||
Child Procedure,Kinderprosedure,
|
||||
Link existing Quality Procedure.,Koppel die bestaande kwaliteitsprosedure.,
|
||||
Additional Information,Bykomende inligting,
|
||||
Quality Review Objective,Doel van gehaltehersiening,
|
||||
@ -9091,7 +9083,6 @@ Unmarked days,Ongemerkte dae,
|
||||
Absent Days,Afwesige dae,
|
||||
Conditions and Formula variable and example,Voorwaardes en formule veranderlike en voorbeeld,
|
||||
Feedback By,Terugvoer deur,
|
||||
MTNG-.YYYY.-.MM.-.DD.-,MTNG-.YYYY .-. MM .-. DD.-,
|
||||
Manufacturing Section,Vervaardigingsafdeling,
|
||||
"By default, the Customer Name is set as per the Full Name entered. If you want Customers to be named by a ",Die kliëntnaam word standaard ingestel volgens die volledige naam wat ingevoer is. As u wil hê dat klante deur 'n,
|
||||
Configure the default Price List when creating a new Sales transaction. Item prices will be fetched from this Price List.,Stel die standaardpryslys op wanneer u 'n nuwe verkoopstransaksie skep. Itempryse word uit hierdie pryslys gehaal.,
|
||||
@ -9692,7 +9683,6 @@ Available Balance,Beskikbare balans,
|
||||
Reserved Balance,Gereserveerde balans,
|
||||
Uncleared Balance,Onduidelike balans,
|
||||
Payment related to {0} is not completed,Betaling wat verband hou met {0} is nie voltooi nie,
|
||||
Row #{}: Serial No{}. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ry # {}: reeksnommer {}. {} is reeds oorgedra na 'n ander POS-faktuur. Kies 'n geldige reeksnr.,
|
||||
Row #{}: Item Code: {} is not available under warehouse {}.,Ry # {}: Itemkode: {} is nie beskikbaar onder pakhuis {} nie.,
|
||||
Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}.,Ry # {}: voorraadhoeveelheid nie genoeg vir artikelkode: {} onder pakhuis {}. Beskikbare hoeveelheid {}.,
|
||||
Row #{}: Please select a serial no and batch against item: {} or remove it to complete transaction.,Ry # {}: kies 'n reeksnommer en 'n bondel teenoor item: {} of verwyder dit om die transaksie te voltooi.,
|
||||
@ -9732,3 +9722,115 @@ Quantity not available for {0} in warehouse {1},Hoeveelheid nie beskikbaar vir {
|
||||
Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.,Aktiveer asseblief Laat negatiewe voorraad toe in voorraadinstellings of skep voorraadinskrywing om voort te gaan.,
|
||||
No Inpatient Record found against patient {0},Geen pasiëntrekord gevind teen pasiënt nie {0},
|
||||
An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Daar bestaan reeds 'n medikasiebevel vir binnepasiënte {0} teen pasiëntontmoeting {1}.,
|
||||
Allow In Returns,Laat opbrengste toe,
|
||||
Hide Unavailable Items,Versteek nie-beskikbare items,
|
||||
Apply Discount on Discounted Rate,Pas afslag toe op afslag,
|
||||
Therapy Plan Template,Terapieplan-sjabloon,
|
||||
Fetching Template Details,Haal sjabloonbesonderhede op,
|
||||
Linked Item Details,Gekoppelde itembesonderhede,
|
||||
Therapy Types,Terapie tipes,
|
||||
Therapy Plan Template Detail,Terapieplan sjabloonbesonderhede,
|
||||
Non Conformance,Nie-ooreenstemming,
|
||||
Process Owner,Proses eienaar,
|
||||
Corrective Action,Korrektiewe aksie,
|
||||
Preventive Action,Voorkomende aksie,
|
||||
Problem,Probleem,
|
||||
Responsible,Verantwoordelik,
|
||||
Completion By,Voltooiing deur,
|
||||
Process Owner Full Name,Proses eienaar se volle naam,
|
||||
Right Index,Regte indeks,
|
||||
Left Index,Linkse indeks,
|
||||
Sub Procedure,Subprosedure,
|
||||
Passed,Geslaag,
|
||||
Print Receipt,Drukbewys,
|
||||
Edit Receipt,Wysig kwitansie,
|
||||
Focus on search input,Fokus op soekinsette,
|
||||
Focus on Item Group filter,Fokus op Item Group filter,
|
||||
Checkout Order / Submit Order / New Order,Afhandeling Bestelling / Dien Bestelling / Nuwe Bestelling in,
|
||||
Add Order Discount,Bestel afslag byvoeg,
|
||||
Item Code: {0} is not available under warehouse {1}.,Itemkode: {0} is nie beskikbaar onder pakhuis {1} nie.,
|
||||
Serial numbers unavailable for Item {0} under warehouse {1}. Please try changing warehouse.,Reeksnommers nie beskikbaar vir item {0} onder pakhuis {1} nie. Probeer om die pakhuis te verander.,
|
||||
Fetched only {0} available serial numbers.,Slegs {0} beskikbare reeksnommers gekry.,
|
||||
Switch Between Payment Modes,Skakel tussen betaalmetodes,
|
||||
Enter {0} amount.,Voer {0} bedrag in.,
|
||||
You don't have enough points to redeem.,U het nie genoeg punte om af te los nie.,
|
||||
You can redeem upto {0}.,U kan tot {0} gebruik.,
|
||||
Enter amount to be redeemed.,Voer die bedrag in wat afgelos moet word.,
|
||||
You cannot redeem more than {0}.,U kan nie meer as {0} gebruik nie.,
|
||||
Open Form View,Maak vormaansig oop,
|
||||
POS invoice {0} created succesfully,POS-faktuur {0} suksesvol geskep,
|
||||
Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.,Voorraadhoeveelheid nie genoeg vir artikelkode: {0} onder pakhuis {1}. Beskikbare hoeveelheid {2}.,
|
||||
Serial No: {0} has already been transacted into another POS Invoice.,Serienommer: {0} is reeds oorgedra na 'n ander POS-faktuur.,
|
||||
Balance Serial No,Saldo Reeksnr,
|
||||
Warehouse: {0} does not belong to {1},Pakhuis: {0} behoort nie tot {1},
|
||||
Please select batches for batched item {0},Kies groepe vir 'n partytjie-item {0},
|
||||
Please select quantity on row {0},Kies hoeveelheid in ry {0},
|
||||
Please enter serial numbers for serialized item {0},Voer die reeksnommers in vir die reeks-item {0},
|
||||
Batch {0} already selected.,Bondel {0} reeds gekies.,
|
||||
Please select a warehouse to get available quantities,Kies 'n pakhuis om beskikbare hoeveelhede te kry,
|
||||
"For transfer from source, selected quantity cannot be greater than available quantity",Vir oordrag vanaf die bron kan die gekose hoeveelheid nie groter wees as die beskikbare hoeveelheid nie,
|
||||
Cannot find Item with this Barcode,Kan nie item met hierdie strepieskode vind nie,
|
||||
{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2},{0} is verpligtend. Miskien word valuta-rekord nie vir {1} tot {2} geskep nie,
|
||||
{} has submitted assets linked to it. You need to cancel the assets to create purchase return.,"{} het bates wat daaraan gekoppel is, ingedien. U moet die bates kanselleer om die aankoopopbrengs te skep.",
|
||||
Cannot cancel this document as it is linked with submitted asset {0}. Please cancel it to continue.,"Kan nie hierdie dokument kanselleer nie, want dit is gekoppel aan die ingediende bate {0}. Kanselleer dit asseblief om voort te gaan.",
|
||||
Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ry # {}: Reeksnr. {} Is reeds oorgedra na 'n ander POS-faktuur. Kies 'n geldige reeksnr.,
|
||||
Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.,Ry # {}: reeksnommers. {} Is reeds in 'n ander POS-faktuur oorgedra. Kies 'n geldige reeksnr.,
|
||||
Item Unavailable,Item nie beskikbaar nie,
|
||||
Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {},"Ry # {}: reeksnommer {} kan nie teruggestuur word nie, aangesien dit nie op die oorspronklike faktuur gedoen is nie {}",
|
||||
Please set default Cash or Bank account in Mode of Payment {},Stel die verstek kontant- of bankrekening in die betaalmetode {},
|
||||
Please set default Cash or Bank account in Mode of Payments {},Stel asseblief die standaard kontant- of bankrekening in die modus van betalings {},
|
||||
Please ensure {} account is a Balance Sheet account. You can change the parent account to a Balance Sheet account or select a different account.,Maak seker dat die {} rekening 'n balansstaatrekening is. U kan die ouerrekening in 'n balansrekening verander of 'n ander rekening kies.,
|
||||
Please ensure {} account is a Payable account. Change the account type to Payable or select a different account.,Maak seker dat die {} rekening 'n betaalbare rekening is. Verander die rekeningtipe na Betaalbaar of kies 'n ander rekening.,
|
||||
Row {}: Expense Head changed to {} ,Ry {}: Onkostekop verander na {},
|
||||
because account {} is not linked to warehouse {} ,omdat rekening {} nie aan pakhuis gekoppel is nie {},
|
||||
or it is not the default inventory account,of dit is nie die standaardvoorraadrekening nie,
|
||||
Expense Head Changed,Uitgawehoof verander,
|
||||
because expense is booked against this account in Purchase Receipt {},omdat die onkoste teen hierdie rekening in die aankoopbewys {} bespreek word,
|
||||
as no Purchase Receipt is created against Item {}. ,aangesien geen aankoopbewys teen item {} geskep word nie.,
|
||||
This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice,Dit word gedoen om rekeningkunde te hanteer vir gevalle waar aankoopbewys na aankoopfaktuur geskep word,
|
||||
Purchase Order Required for item {},Bestelling benodig vir item {},
|
||||
To submit the invoice without purchase order please set {} ,Stel die {} in om die faktuur sonder 'n bestelling in te dien,
|
||||
as {} in {},soos in {},
|
||||
Mandatory Purchase Order,Verpligte bestelling,
|
||||
Purchase Receipt Required for item {},Aankoopbewys benodig vir item {},
|
||||
To submit the invoice without purchase receipt please set {} ,Stel die {} in om die faktuur sonder aankoopbewys in te dien.,
|
||||
Mandatory Purchase Receipt,Verpligte aankoopbewys,
|
||||
POS Profile {} does not belongs to company {},POS-profiel {} behoort nie tot die maatskappy nie {},
|
||||
User {} is disabled. Please select valid user/cashier,Gebruiker {} is gedeaktiveer. Kies 'n geldige gebruiker / kassier,
|
||||
Row #{}: Original Invoice {} of return invoice {} is {}. ,Ry # {}: oorspronklike faktuur {} van retourfaktuur {} is {}.,
|
||||
Original invoice should be consolidated before or along with the return invoice.,Die oorspronklike faktuur moet voor of saam met die retoervaktuur gekonsolideer word.,
|
||||
You can add original invoice {} manually to proceed.,U kan oorspronklike fakture {} handmatig byvoeg om voort te gaan.,
|
||||
Please ensure {} account is a Balance Sheet account. ,Maak seker dat die {} rekening 'n balansstaatrekening is.,
|
||||
You can change the parent account to a Balance Sheet account or select a different account.,U kan die ouerrekening in 'n balansrekening verander of 'n ander rekening kies.,
|
||||
Please ensure {} account is a Receivable account. ,Maak seker dat die {} rekening 'n ontvangbare rekening is.,
|
||||
Change the account type to Receivable or select a different account.,Verander die rekeningtipe na Ontvangbaar of kies 'n ander rekening.,
|
||||
{} can't be cancelled since the Loyalty Points earned has been redeemed. First cancel the {} No {},{} kan nie gekanselleer word nie omdat die verdienste van die Lojaliteitspunte afgelos is. Kanselleer eers die {} Nee {},
|
||||
already exists,bestaan alreeds,
|
||||
POS Closing Entry {} against {} between selected period,POS-sluitingsinskrywing {} teen {} tussen die gekose periode,
|
||||
POS Invoice is {},POS-faktuur is {},
|
||||
POS Profile doesn't matches {},POS-profiel stem nie ooreen nie {},
|
||||
POS Invoice is not {},POS-faktuur is nie {},
|
||||
POS Invoice isn't created by user {},POS-faktuur word nie deur gebruiker {} geskep nie,
|
||||
Row #{}: {},Ry # {}: {},
|
||||
Invalid POS Invoices,Ongeldige POS-fakture,
|
||||
Please add the account to root level Company - {},Voeg die rekening by die maatskappy se wortelvlak - {},
|
||||
"While creating account for Child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA","Terwyl u 'n rekening vir Child Company {0} skep, word die ouerrekening {1} nie gevind nie. Skep asseblief die ouerrekening in ooreenstemmende COA",
|
||||
Account Not Found,Rekening nie gevind nie,
|
||||
"While creating account for Child Company {0}, parent account {1} found as a ledger account.","Terwyl u 'n rekening vir Child Company {0} skep, word die ouerrekening {1} as 'n grootboekrekening gevind.",
|
||||
Please convert the parent account in corresponding child company to a group account.,Skakel asseblief die ouerrekening in die ooreenstemmende kindermaatskappy om na 'n groeprekening.,
|
||||
Invalid Parent Account,Ongeldige ouerrekening,
|
||||
"Renaming it is only allowed via parent company {0}, to avoid mismatch.","Om dit te hernoem, is slegs toegelaat via moedermaatskappy {0}, om wanverhouding te voorkom.",
|
||||
"If you {0} {1} quantities of the item {2}, the scheme {3} will be applied on the item.","As u {0} {1} hoeveelhede van die artikel {2} het, sal die skema {3} op die item toegepas word.",
|
||||
"If you {0} {1} worth item {2}, the scheme {3} will be applied on the item.","As u {0} {1} die waarde van item {2} het, sal die skema {3} op die item toegepas word.",
|
||||
"As the field {0} is enabled, the field {1} is mandatory.","Aangesien die veld {0} geaktiveer is, is die veld {1} verpligtend.",
|
||||
"As the field {0} is enabled, the value of the field {1} should be more than 1.","Aangesien die veld {0} geaktiveer is, moet die waarde van die veld {1} meer as 1 wees.",
|
||||
Cannot deliver Serial No {0} of item {1} as it is reserved to fullfill Sales Order {2},"Kan nie reeksnommer {0} van die artikel {1} lewer nie, aangesien dit gereserveer is vir die volledige bestelling {2}",
|
||||
"Sales Order {0} has reservation for the item {1}, you can only deliver reserved {1} against {0}.",Verkooporder {0} het 'n bespreking vir die artikel {1}. U kan slegs gereserveerde {1} teen {0} aflewer.,
|
||||
{0} Serial No {1} cannot be delivered,{0} Reeksnr. {1} kan nie afgelewer word nie,
|
||||
Row {0}: Subcontracted Item is mandatory for the raw material {1},Ry {0}: Item uit die onderkontrak is verpligtend vir die grondstof {1},
|
||||
"As there are sufficient raw materials, Material Request is not required for Warehouse {0}.","Aangesien daar voldoende grondstowwe is, is materiaalversoek nie nodig vir pakhuis {0} nie.",
|
||||
" If you still want to proceed, please enable {0}.",Skakel {0} aan as u nog steeds wil voortgaan.,
|
||||
The item referenced by {0} - {1} is already invoiced,Die item waarna verwys word deur {0} - {1} word reeds gefaktureer,
|
||||
Therapy Session overlaps with {0},Terapiesessie oorvleuel met {0},
|
||||
Therapy Sessions Overlapping,Terapiesessies oorvleuel,
|
||||
Therapy Plans,Terapieplanne,
|
||||
|
Can't render this file because it is too large.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user