Merge branch 'staging' into develop

This commit is contained in:
Frappe Bot 2018-12-26 12:16:20 +00:00
commit 9e09b3adbe
62 changed files with 1781 additions and 1131 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '10.1.74'
__version__ = '10.1.76'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -830,6 +830,10 @@ class PurchaseInvoice(BuyingController):
return
tax_withholding_details = get_party_tax_withholding_details(self)
if not tax_withholding_details:
return
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
@ -839,6 +843,12 @@ class PurchaseInvoice(BuyingController):
if not accounts or tax_withholding_details.get("account_head") not in accounts:
self.append("taxes", tax_withholding_details)
to_remove = [d for d in self.taxes
if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
for d in to_remove:
self.remove(d)
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()

View File

@ -324,7 +324,8 @@ class SalesInvoice(SellingController):
return {
"print_format": print_format,
"allow_edit_rate": pos.get("allow_user_to_edit_rate"),
"allow_edit_discount": pos.get("allow_user_to_edit_discount")
"allow_edit_discount": pos.get("allow_user_to_edit_discount"),
"campaign": pos.get("campaign")
}
def update_time_sheet(self, sales_invoice):

View File

@ -1,4 +1,4 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
@ -762,6 +762,20 @@ class TestSalesInvoice(unittest.TestCase):
set_perpetual_inventory(0)
frappe.db.sql("delete from `tabPOS Profile`")
def test_pos_si_without_payment(self):
set_perpetual_inventory()
make_pos_profile()
pos = copy.deepcopy(test_records[1])
pos["is_pos"] = 1
pos["update_stock"] = 1
si = frappe.copy_doc(pos)
si.insert()
# Check that the invoice cannot be submitted without payments
self.assertRaises(frappe.ValidationError, si.submit)
def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
set_perpetual_inventory()

View File

@ -24,6 +24,7 @@ def get_party_tax_withholding_details(ref_doc):
.format(tax_withholding_category, ref_doc.company))
tds_amount = get_tds_amount(ref_doc, tax_details, fy)
tax_row = get_tax_row(tax_details, tds_amount)
return tax_row
def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
@ -62,46 +63,64 @@ def get_tax_row(tax_details, tds_amount):
def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
fiscal_year, year_start_date, year_end_date = fiscal_year_details
tds_amount = 0
tds_deducted = 0
def _get_tds():
tds_amount = 0
if not tax_details.threshold or ref_doc.net_total >= tax_details.threshold:
tds_amount = ref_doc.net_total * tax_details.rate / 100
return tds_amount
def _get_tds(amount):
if amount <= 0:
return 0
if tax_details.cumulative_threshold:
entries = frappe.db.sql("""
return amount * tax_details.rate / 100
entries = frappe.db.sql("""
select voucher_no, credit
from `tabGL Entry`
where party=%s and fiscal_year=%s and credit > 0
""", (ref_doc.supplier, fiscal_year), as_dict=1)
supplier_credit_amount = flt(sum([d.credit for d in entries]))
vouchers = [d.voucher_no for d in entries]
advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
vouchers = [d.voucher_no for d in entries]
vouchers += get_advance_vouchers(ref_doc.supplier, fiscal_year)
tds_vouchers = vouchers + advance_vouchers
tds_deducted = 0
if vouchers:
tds_deducted = flt(frappe.db.sql("""
select sum(credit)
from `tabGL Entry`
where account=%s and fiscal_year=%s and credit > 0
and voucher_no in ({0})
""".format(', '.join(["'%s'" % d for d in vouchers])),
(tax_details.account_head, fiscal_year))[0][0])
if tds_vouchers:
tds_deducted = frappe.db.sql("""
SELECT sum(credit) FROM `tabGL Entry`
WHERE
account=%s and fiscal_year=%s and credit > 0
and voucher_no in ({0})""". format(','.join(['%s'] * len(tds_vouchers))),
((tax_details.account_head, fiscal_year) + tuple(tds_vouchers)))
tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
if tds_deducted:
tds_amount = _get_tds(ref_doc.net_total)
else:
supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
fields = ['sum(net_amount)'],
filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1)
supplier_credit_amount = (supplier_credit_amount[0][0]
if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
jv_supplier_credit_amt = frappe.get_all('Journal Entry Account',
fields = ['sum(credit_in_account_currency)'],
filters = {
'parent': ('in', vouchers), 'docstatus': 1,
'party': ref_doc.supplier,
'reference_type': ('not in', ['Purchase Invoice'])
}, as_list=1)
supplier_credit_amount += (jv_supplier_credit_amt[0][0]
if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
supplier_credit_amount += ref_doc.net_total
debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date)
supplier_credit_amount -= debit_note_amount
total_invoiced_amount = supplier_credit_amount + tds_deducted \
+ flt(ref_doc.net_total) - debit_note_amount
if total_invoiced_amount >= tax_details.cumulative_threshold:
total_applicable_tds = total_invoiced_amount * tax_details.rate / 100
tds_amount = min(total_applicable_tds - tds_deducted, ref_doc.net_total)
else:
tds_amount = _get_tds()
else:
tds_amount = _get_tds()
if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
tds_amount = _get_tds(supplier_credit_amount)
return tds_amount
@ -114,7 +133,7 @@ def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=Non
select distinct voucher_no
from `tabGL Entry`
where party=%s and %s and debit > 0
""", (supplier, condition))
""", (supplier, condition)) or []
def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
condition = ""
@ -126,4 +145,4 @@ def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None
from `tabPurchase Invoice`
where supplier=%s %s and is_return=1 and docstatus=1
and posting_date between %s and %s
""", (supplier, condition, year_start_date, year_end_date)))
""", (supplier, condition, year_start_date, year_end_date)))

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
import unittest
from frappe.utils import today
from erpnext.accounts.utils import get_fiscal_year
test_dependencies = ["Supplier Group"]
@ -14,65 +15,105 @@ class TestTaxWithholdingCategory(unittest.TestCase):
def setUpClass(self):
# create relevant supplier, etc
create_records()
create_tax_with_holding_category()
def test_single_threshold_tds(self):
frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194D - Individual")
pi = create_purchase_invoice()
def test_cumulative_threshold_tds(self):
frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "Cumulative Threshold TDS")
invoices = []
# create invoices for lower than single threshold tax rate
for _ in xrange(2):
pi = create_purchase_invoice(supplier = "Test TDS Supplier")
pi.submit()
invoices.append(pi)
# create another invoice whose total when added to previously created invoice,
# surpasses cumulative threshhold
pi = create_purchase_invoice(supplier = "Test TDS Supplier")
pi.submit()
self.assertEqual(pi.taxes_and_charges_deducted, 800)
self.assertEqual(pi.grand_total, 15200)
# assert equal tax deduction on total invoice amount uptil now
self.assertEqual(pi.taxes_and_charges_deducted, 3000)
self.assertEqual(pi.grand_total, 7000)
invoices.append(pi)
# TDS is already deducted, so from onward system will deduct the TDS on every invoice
pi = create_purchase_invoice(supplier = "Test TDS Supplier", rate=5000)
pi.submit()
# assert equal tax deduction on total invoice amount uptil now
self.assertEqual(pi.taxes_and_charges_deducted, 500)
invoices.append(pi)
#delete invoices to avoid clashing
for d in invoices:
d.cancel()
frappe.delete_doc("Purchase Invoice", d.name)
def test_single_threshold_tds(self):
invoices = []
frappe.db.set_value("Supplier", "Test TDS Supplier1", "tax_withholding_category", "Single Threshold TDS")
pi = create_purchase_invoice(supplier = "Test TDS Supplier1", rate = 20000)
pi.submit()
invoices.append(pi)
self.assertEqual(pi.taxes_and_charges_deducted, 2000)
self.assertEqual(pi.grand_total, 18000)
# check gl entry for the purchase invoice
gl_entries = frappe.db.get_all('GL Entry', filters={'voucher_no': pi.name}, fields=["*"])
self.assertEqual(len(gl_entries), 3)
for d in gl_entries:
if d.account == pi.credit_to:
self.assertEqual(d.credit, 15200)
self.assertEqual(d.credit, 18000)
elif d.account == pi.items[0].get("expense_account"):
self.assertEqual(d.debit, 16000)
self.assertEqual(d.debit, 20000)
elif d.account == pi.taxes[0].get("account_head"):
self.assertEqual(d.credit, 800)
self.assertEqual(d.credit, 2000)
else:
raise ValueError("Account head does not match.")
# delete purchase invoice to avoid it interefering in other tests
pi.cancel()
frappe.delete_doc('Purchase Invoice', pi.name)
def test_cumulative_threshold_tds(self):
frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194C - Individual")
invoices = []
# create invoices for lower than single threshold tax rate
for _ in xrange(6):
pi = create_purchase_invoice()
pi.submit()
invoices.append(pi)
# create another invoice whose total when added to previously created invoice,
# surpasses cumulative threshhold
pi = create_purchase_invoice()
pi = create_purchase_invoice(supplier = "Test TDS Supplier1")
pi.submit()
# assert equal tax deduction on total invoice amount uptil now
self.assertEqual(pi.taxes_and_charges_deducted, 1120)
self.assertEqual(pi.grand_total, 14880)
invoices.append(pi)
# TDS amount is 1000 because in previous invoices it's already deducted
self.assertEqual(pi.taxes_and_charges_deducted, 1000)
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
frappe.delete_doc("Purchase Invoice", d.name)
def create_purchase_invoice(qty=1):
def test_single_threshold_tds_with_previous_vouchers(self):
invoices = []
frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS")
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
self.assertEqual(pi.taxes_and_charges_deducted, 2000)
self.assertEqual(pi.grand_total, 8000)
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
frappe.delete_doc("Purchase Invoice", d.name)
def create_purchase_invoice(**args):
# return sales invoice doc object
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
args = frappe._dict(args)
pi = frappe.get_doc({
"doctype": "Purchase Invoice",
"posting_date": today(),
"apply_tds": 1,
"supplier": frappe.get_doc('Supplier', {"supplier_name": "Test TDS Supplier"}).name,
"supplier": args.supplier,
"company": '_Test Company',
"taxes_and_charges": "",
"currency": "INR",
@ -81,8 +122,8 @@ def create_purchase_invoice(qty=1):
"items": [{
'doctype': 'Purchase Invoice Item',
'item_code': item.name,
'qty': qty,
'rate': 16000,
'qty': args.qty or 1,
'rate': args.rate or 10000,
'cost_center': 'Main - _TC',
'expense_account': 'Stock Received But Not Billed - _TC'
}]
@ -92,20 +133,73 @@ def create_purchase_invoice(qty=1):
return pi
def create_records():
# create a new supplier
frappe.get_doc({
"supplier_group": "_Test Supplier Group",
"supplier_name": "Test TDS Supplier",
"doctype": "Supplier",
"tax_withholding_category": "TDS - 194D - Individual"
}).insert()
# create a new suppliers
for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
if frappe.db.exists('Supplier', name):
continue
frappe.get_doc({
"supplier_group": "_Test Supplier Group",
"supplier_name": name,
"doctype": "Supplier",
}).insert()
# create an item
frappe.get_doc({
"doctype": "Item",
"item_code": "TDS Item",
"item_name": "TDS Item",
"item_group": "All Item Groups",
"company": "_Test Company",
"is_stock_item": 0,
}).insert()
if not frappe.db.exists('Item', "TDS Item"):
frappe.get_doc({
"doctype": "Item",
"item_code": "TDS Item",
"item_name": "TDS Item",
"item_group": "All Item Groups",
"is_stock_item": 0,
}).insert()
# create an account
if not frappe.db.exists("Account", "TDS - _TC"):
frappe.get_doc({
'doctype': 'Account',
'company': '_Test Company',
'account_name': 'TDS',
'parent_account': 'Tax Assets - _TC',
'report_type': 'Balance Sheet',
'root_type': 'Asset'
}).insert()
def create_tax_with_holding_category():
fiscal_year = get_fiscal_year(today(), company="_Test Company")[0]
# Cummulative thresold
if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"):
frappe.get_doc({
"doctype": "Tax Withholding Category",
"name": "Cumulative Threshold TDS",
"category_name": "10% TDS",
"rates": [{
'fiscal_year': fiscal_year,
'tax_withholding_rate': 10,
'single_threshold': 0,
'cumulative_threshold': 30000.00
}],
"accounts": [{
'company': '_Test Company',
'account': 'TDS - _TC'
}]
}).insert()
# Single thresold
if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"):
frappe.get_doc({
"doctype": "Tax Withholding Category",
"name": "Single Threshold TDS",
"category_name": "10% TDS",
"rates": [{
'fiscal_year': fiscal_year,
'tax_withholding_rate': 10,
'single_threshold': 20000.00,
'cumulative_threshold': 0
}],
"accounts": [{
'company': '_Test Company',
'account': 'TDS - _TC'
}]
}).insert()

View File

@ -1135,16 +1135,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
apply_category: function() {
var me = this;
category = this.selected_item_group || "All Item Groups";
frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
category = this.selected_item_group || r.name;
if(category == 'All Item Groups') {
return this.item_data
} else {
return this.item_data.filter(function(element, index, array){
return element.item_group == category;
});
}
if(category == r.name) {
return this.item_data
} else {
return this.item_data.filter(function(element, index, array){
return element.item_group == category;
});
}
})
},
bind_items_event: function() {

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
from frappe.model.utils import get_fetch_values
from frappe.utils import (add_days, getdate, formatdate, date_diff,
add_years, get_timestamp, nowdate, flt, add_months, get_last_day)
@ -151,10 +151,7 @@ def get_default_price_list(party):
def set_price_list(out, party, party_type, given_price_list):
# price list
price_list = filter(None, get_user_permissions()
.get("Price List", {})
.get("docs", []))
price_list = list(price_list)
price_list = get_permitted_documents('Price List')
if price_list:
price_list = price_list[0]

View File

@ -91,6 +91,7 @@ class PurchaseOrder(BuyingController):
self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company)
def validate_minimum_order_qty(self):
if not self.get("items"): return
items = list(set([d.item_code for d in self.get("items")]))
itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty

View File

@ -561,10 +561,6 @@ def get_data():
"label": _("Subscription Management"),
"icon": "fa fa-microchip ",
"items": [
{
"type": "doctype",
"name": "Subscriber",
},
{
"type": "doctype",
"name": "Subscription Plan",

View File

@ -678,7 +678,7 @@ class BuyingController(StockController):
frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self):
if not self.schedule_date:
if not self.schedule_date and self.get("items"):
self.schedule_date = min([d.schedule_date for d in self.get("items")])
if self.schedule_date:

View File

@ -12,6 +12,9 @@ from erpnext.controllers.accounts_controller import AccountsController
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.stock import get_warehouse_account_map
class QualityInspectionRequiredError(frappe.ValidationError): pass
class QualityInspectionRejectedError(frappe.ValidationError): pass
class StockController(AccountsController):
def validate(self):
super(StockController, self).validate()
@ -317,7 +320,6 @@ class StockController(AccountsController):
def validate_inspection(self):
'''Checks if quality inspection is set for Items that require inspection.
On submit, throw an exception'''
inspection_required_fieldname = None
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
inspection_required_fieldname = "inspection_required_before_purchase"
@ -330,17 +332,25 @@ class StockController(AccountsController):
return
for d in self.get('items'):
raise_exception = False
qa_required = False
if (inspection_required_fieldname and not d.quality_inspection and
frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)):
raise_exception = True
qa_required = True
elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
raise_exception = True
qa_required = True
if raise_exception:
if qa_required:
frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
if self.docstatus==1:
raise frappe.ValidationError
raise QualityInspectionRequiredError
elif self.docstatus == 1:
if d.quality_inspection:
qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
if qa_failed:
frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
.format(d.idx, d.item_code), QualityInspectionRejectedError)
def update_blanket_order(self):
blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order]))

View File

@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
develop_version = '12.x.x-develop'
staging_version = '11.0.3-beta.31'
staging_version = '11.0.3-beta.32'
error_report_email = "support@erpnext.com"

View File

@ -62,8 +62,8 @@ class Employee(NestedSet):
def validate_user_details(self):
data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1)
self.image = data.get("user_image")
if data.get("user_image"):
self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id()

View File

@ -14,7 +14,7 @@ frappe.ui.form.on("Leave Application", {
doctype: frm.doc.doctype
}
};
});
});
frm.set_query("employee", erpnext.queries.employee);
},
@ -83,7 +83,7 @@ frappe.ui.form.on("Leave Application", {
if (!frm.doc.employee && frappe.defaults.get_user_permissions()) {
const perm = frappe.defaults.get_user_permissions();
if (perm && perm['Employee']) {
frm.set_value('employee', perm['Employee']["docs"][0])
frm.set_value('employee', perm['Employee'].map(perm_doc => perm_doc.doc)[0]);
}
}
},

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cint
from frappe.utils import flt, cint, cstr
from frappe import _
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
@ -22,7 +22,7 @@ class SalaryStructure(Document):
overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"]
for table in ["earnings", "deductions"]:
for d in self.get(table):
component_default_value = frappe.db.get_value("Salary Component", str(d.salary_component),
component_default_value = frappe.db.get_value("Salary Component", cstr(d.salary_component),
overwritten_fields + overwritten_fields_if_missing, as_dict=1)
if component_default_value:
for fieldname in overwritten_fields:

View File

@ -402,6 +402,8 @@ frappe.ui.form.on("BOM Item", "items_remove", function(frm) {
var toggle_operations = function(frm) {
frm.toggle_display("operations_section", cint(frm.doc.with_operations) == 1);
frm.toggle_display("transfer_material_against", cint(frm.doc.with_operations) == 1);
frm.toggle_reqd("transfer_material_against", cint(frm.doc.with_operations) == 1);
};
frappe.ui.form.on("BOM", "with_operations", function(frm) {

View File

@ -80,41 +80,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
"fieldname": "quantity",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity",
"length": 0,
"no_copy": 0,
"oldfieldname": "quantity",
"oldfieldtype": "Currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -154,8 +119,10 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "inspection_required",
"fieldtype": "Check",
"default": "1",
"description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
"fieldname": "quantity",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -163,51 +130,18 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Inspection Required",
"label": "Quantity",
"length": 0,
"no_copy": 0,
"oldfieldname": "quantity",
"oldfieldtype": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "inspection_required",
"fieldname": "quality_inspection_template",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quality Inspection Template",
"length": 0,
"no_copy": 0,
"options": "Quality Inspection Template",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@ -346,77 +280,11 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rm_cost_as_per",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate Of Materials Based On",
"length": 0,
"no_copy": 0,
"options": "Valuation Rate\nLast Purchase Rate\nPrice List",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
"fieldname": "buying_price_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
"fieldname": "inspection_required",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -425,7 +293,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Set rate of sub-assembly item based on BOM",
"label": "Inspection Required",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -481,7 +349,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "allow_same_item_multiple_times",
"fieldtype": "Data",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -508,12 +376,12 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "with_operations",
"fieldname": "transfer_material_against_job_card",
"default": "1",
"fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -522,7 +390,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transfer Material Against Job Card",
"label": "Set rate of sub-assembly item based on BOM",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -538,6 +406,40 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "inspection_required",
"fieldname": "quality_inspection_template",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quality Inspection Template",
"length": 0,
"no_copy": 0,
"options": "Quality Inspection Template",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -603,6 +505,72 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "transfer_material_against",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transfer Material Against",
"length": 0,
"no_copy": 0,
"options": "\nWork Order\nJob Card",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "conversion_rate",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Conversion Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "9",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -670,12 +638,12 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "conversion_rate",
"fieldtype": "Float",
"fieldname": "rm_cost_as_per",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -683,17 +651,50 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Conversion Rate",
"label": "Rate Of Materials Based On",
"length": 0,
"no_copy": 0,
"options": "Valuation Rate\nLast Purchase Rate\nPrice List",
"permlevel": 0,
"precision": "9",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
"fieldname": "buying_price_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@ -707,7 +708,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "Specify the operations, operating cost and give a unique Operation no to your operations.",
"description": "",
"fieldname": "operations_section",
"fieldtype": "Section Break",
"hidden": 0,
@ -1976,7 +1977,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-24 02:07:21.618275",
"modified": "2018-12-13 17:45:44.843197",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@ -81,7 +81,7 @@ class BOM(WebsiteGenerator):
def get_item_det(self, item_code):
item = frappe.db.sql("""select name, item_name, docstatus, description, image,
is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, allow_transfer_for_manufacture
is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, include_item_in_manufacturing
from `tabItem` where name=%s""", item_code, as_dict = 1)
if not item:
@ -109,7 +109,7 @@ class BOM(WebsiteGenerator):
"item_name": item.item_name,
"bom_no": item.bom_no,
"stock_qty": item.stock_qty,
"allow_transfer_for_manufacture": item.allow_transfer_for_manufacture
"include_item_in_manufacturing": item.include_item_in_manufacturing
})
for r in ret:
if not item.get(r):
@ -128,8 +128,8 @@ class BOM(WebsiteGenerator):
self.validate_rm_item(item)
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
args['transfer_for_manufacture'] = (cstr(args.get('allow_transfer_for_manufacture', '')) or
item and item[0].allow_transfer_for_manufacture or 0)
args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or
item and item[0].include_item_in_manufacturing or 0)
args.update(item[0])
rate = self.get_rm_rate(args)
@ -145,7 +145,7 @@ class BOM(WebsiteGenerator):
'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate,
'allow_transfer_for_manufacture': cint(args['transfer_for_manufacture']) or 0
'include_item_in_manufacturing': cint(args['transfer_for_manufacture']) or 0
}
return ret_item
@ -479,7 +479,7 @@ class BOM(WebsiteGenerator):
'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate,
'allow_transfer_for_manufacture': d.allow_transfer_for_manufacture
'include_item_in_manufacturing': d.include_item_in_manufacturing
}))
def company_currency(self):
@ -496,7 +496,7 @@ class BOM(WebsiteGenerator):
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name,
bom_item.description, bom_item.source_warehouse, bom_item.operation,
bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.allow_transfer_for_manufacture,
bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.include_item_in_manufacturing,
bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
from `tabBOM Explosion Item` bom_item, tabBOM bom
where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
@ -511,7 +511,7 @@ class BOM(WebsiteGenerator):
'stock_uom' : d['stock_uom'],
'stock_qty' : d['qty_consumed_per_unit'] * stock_qty,
'rate' : flt(d['rate']),
'allow_transfer_for_manufacture': d.get('allow_transfer_for_manufacture', 0)
'include_item_in_manufacturing': d.get('include_item_in_manufacturing', 0)
}))
def add_exploded_items(self):
@ -587,7 +587,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
query = query.format(table="BOM Explosion Item",
where_conditions="",
is_stock_item=is_stock_item,
select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.allow_transfer_for_manufacture,
select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.include_item_in_manufacturing,
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s ) as idx""")
items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
@ -596,7 +596,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
else:
query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item,
select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.allow_transfer_for_manufacture")
select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing")
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
for item in items:

View File

@ -11,7 +11,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
},
{
"amount": 2000.0,
@ -23,7 +23,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@ -57,7 +57,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
},
{
"amount": 2000.0,
@ -69,7 +69,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@ -102,7 +102,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
},
{
"amount": 3000.0,
@ -115,7 +115,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@ -150,7 +150,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1
"include_item_in_manufacturing": 1
}
],
"docstatus": 1,

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -573,7 +574,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_transfer_for_manufacture",
"fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -582,7 +583,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Transfer for Manufacture",
"label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -609,7 +610,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-08-27 16:32:35.152139",
"modified": "2018-11-20 19:04:59.813773",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Explosion Item",

View File

@ -79,34 +79,67 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "operation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item operation",
"length": 0,
"no_copy": 0,
"options": "Operation",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -932,8 +965,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "item_code.allow_transfer_for_manufacture",
"fieldname": "allow_transfer_for_manufacture",
"fetch_from": "item_code.include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -942,7 +974,6 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Transfer for Manufacture",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -956,6 +987,29 @@
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -1023,6 +1077,38 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_alternative_item",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Alternative Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -1035,7 +1121,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-11-22 15:04:55.187136",
"modified": "2018-12-26 15:04:56.187136",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",

View File

@ -3,7 +3,7 @@
frappe.ui.form.on('Job Card', {
refresh: function(frm) {
if (frm.doc.items && frm.doc.docstatus==1) {
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request");
@ -31,6 +31,7 @@ frappe.ui.form.on('Job Card', {
frm.add_custom_button(__("Complete Job"), () => {
frm.set_value('actual_end_date', frappe.datetime.now_datetime());
frm.save();
frm.savesubmit();
});
}
}

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -46,6 +47,39 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bom_no",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM No",
"length": 0,
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -112,39 +146,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "WIP Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -281,9 +282,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "transferred_qty",
"fieldtype": "Float",
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -291,17 +291,18 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transferred Qty",
"label": "WIP Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@ -635,8 +636,9 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bom_no",
"fieldtype": "Link",
"default": "0",
"fieldname": "transferred_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -644,10 +646,42 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM No",
"label": "Transferred Qty",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "requested_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Requested Qty",
"length": 0,
"no_copy": 0,
"options": "BOM",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -701,8 +735,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_20",
"fieldtype": "Column Break",
"fieldname": "remarks",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -710,6 +744,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Remarks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -732,8 +767,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "remarks",
"fieldtype": "Small Text",
"fieldname": "column_break_20",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -741,7 +776,6 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Remarks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -776,13 +810,13 @@
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "Open\nWork In Progress\nCancelled\nCompleted",
"no_copy": 1,
"options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -834,7 +868,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-28 16:50:43.576151",
"modified": "2018-12-13 17:23:57.986381",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",

View File

@ -11,9 +11,9 @@ from frappe.model.document import Document
class JobCard(Document):
def validate(self):
self.status = 'Open'
self.validate_actual_dates()
self.set_time_in_mins()
self.set_status()
def validate_actual_dates(self):
if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date):
@ -48,7 +48,7 @@ class JobCard(Document):
return
doc = frappe.get_doc('Work Order', self.get('work_order'))
if not doc.transfer_material_against_job_card and doc.skip_transfer:
if doc.transfer_material_against == 'Work Order' and doc.skip_transfer:
return
for d in doc.required_items:
@ -104,20 +104,23 @@ class JobCard(Document):
wo.set_actual_dates()
wo.save()
def set_transferred_qty(self):
def set_transferred_qty(self, update_status=False):
if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
if self.items:
self.transferred_qty = frappe.db.get_value('Stock Entry', {'job_card': self.name,
'work_order': self.work_order, 'docstatus': 1}, 'sum(fg_completed_qty)') or 0
self.transferred_qty = frappe.db.get_value('Stock Entry', {
'job_card': self.name,
'work_order': self.work_order,
'docstatus': 1
}, 'sum(fg_completed_qty)') or 0
self.db_set("transferred_qty", self.transferred_qty)
qty = 0
if self.work_order:
doc = frappe.get_doc('Work Order', self.work_order)
if doc.transfer_material_against_job_card and not doc.skip_transfer:
if doc.transfer_material_against == 'Job Card' and not doc.skip_transfer:
completed = True
for d in doc.operations:
if d.status != 'Completed':
@ -131,15 +134,28 @@ class JobCard(Document):
doc.db_set('material_transferred_for_manufacturing', qty)
self.set_status()
self.set_status(update_status)
def set_status(self):
status = 'Cancelled' if self.docstatus == 2 else 'Work In Progress'
def set_status(self, update_status=False):
self.status = {
0: "Open",
1: "Submitted",
2: "Cancelled"
}[self.docstatus or 0]
if self.for_quantity == self.transferred_qty:
status = 'Completed'
if self.actual_start_date:
self.status = 'Work In Progress'
self.db_set('status', status)
if (self.docstatus == 1 and
(self.for_quantity == self.transferred_qty or not self.items)):
self.status = 'Completed'
if self.status != 'Completed':
if self.for_quantity == self.transferred_qty:
self.status = 'Material Transferred'
if update_status:
self.db_set('status', self.status)
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):

View File

@ -6,6 +6,8 @@ frappe.listview_settings['Job Card'] = {
return [__("Completed"), "green", "status,=,Completed"];
} else if (doc.docstatus == 2) {
return [__("Cancelled"), "red", "status,=,Cancelled"];
} else if (doc.status === "Material Transferred") {
return [__('Material Transferred'), "blue", "status,=,Material Transferred"];
} else {
return [__("Open"), "red", "status,=,Open"];
}

View File

@ -306,7 +306,7 @@ class TestWorkOrder(unittest.TestCase):
items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0}
for item, allow_transfer in items.items():
make_item(item, {
'allow_transfer_for_manufacture': allow_transfer
'include_item_in_manufacturing': allow_transfer
})
fg_item = 'Finished Good Transfer Item'

View File

@ -112,11 +112,20 @@ frappe.ui.form.on("Work Order", {
frm.trigger('show_progress');
}
if (frm.doc.docstatus === 1 && frm.doc.operations
if (frm.doc.docstatus === 1
&& frm.doc.operations && frm.doc.operations.length
&& frm.doc.qty != frm.doc.material_transferred_for_manufacturing) {
frm.add_custom_button(__('Make Job Card'), () => {
frm.trigger("make_job_card")
}).addClass('btn-primary');
const not_completed = frm.doc.operations.filter(d => {
if(d.status != 'Completed') {
return true;
}
});
if(not_completed && not_completed.length) {
frm.add_custom_button(__('Make Job Card'), () => {
frm.trigger("make_job_card")
}).addClass('btn-primary');
}
}
if(frm.doc.required_items && frm.doc.allow_alternative_item) {
@ -294,7 +303,7 @@ frappe.ui.form.on("Work Order", {
frm.trigger('set_sales_order');
erpnext.in_production_item_onchange = true;
$.each(["description", "stock_uom", "project", "bom_no",
"allow_alternative_item", "transfer_material_against_job_card"], function(i, field) {
"allow_alternative_item", "transfer_material_against"], function(i, field) {
frm.set_value(field, r.message[field]);
});
@ -340,9 +349,8 @@ frappe.ui.form.on("Work Order", {
before_submit: function(frm) {
frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
if (frm.doc.operations) {
frm.fields_dict.operations.grid.toggle_reqd("workstation", true);
}
frm.toggle_reqd("transfer_material_against", frm.doc.operations);
frm.fields_dict.operations.grid.toggle_reqd("workstation", frm.doc.operations);
},
set_sales_order: function(frm) {
@ -425,7 +433,7 @@ erpnext.work_order = {
}
const show_start_btn = (frm.doc.skip_transfer
|| frm.doc.transfer_material_against_job_card) ? 0 : 1;
|| frm.doc.transfer_material_against == 'Job Card') ? 0 : 1;
if (show_start_btn){
if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty))

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@ -183,6 +184,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_alternative_item",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Alternative Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -223,7 +256,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_alternative_item",
"description": "Check if material transfer entry is not required",
"fieldname": "skip_transfer",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -232,7 +266,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Alternative Item",
"label": "Skip Material Transfer",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -486,39 +520,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "Check if material transfer entry is not required",
"fieldname": "skip_transfer",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Skip Material Transfer",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -552,39 +553,6 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "operations",
"fieldname": "transfer_material_against_job_card",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transfer Material Against Job Card",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1070,6 +1038,41 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Work Order",
"depends_on": "operations",
"fieldname": "transfer_material_against",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Transfer Material Against",
"length": 0,
"no_copy": 0,
"options": "\nWork Order\nJob Card",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -1672,7 +1675,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-09-05 06:28:22.983369",
"modified": "2018-12-13 15:33:12.490710",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order",

View File

@ -191,7 +191,7 @@ class WorkOrder(Document):
for purpose, fieldname in (("Manufacture", "produced_qty"),
("Material Transfer for Manufacture", "material_transferred_for_manufacturing")):
if (purpose == 'Material Transfer for Manufacture' and
self.operations and self.transfer_material_against_job_card):
self.operations and self.transfer_material_against == 'Job Card'):
continue
qty = flt(frappe.db.sql("""select sum(fg_completed_qty)
@ -459,7 +459,7 @@ class WorkOrder(Document):
'allow_alternative_item': item.allow_alternative_item,
'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse,
'allow_transfer_for_manufacture': item.allow_transfer_for_manufacture
'include_item_in_manufacturing': item.include_item_in_manufacturing
})
self.set_available_qty()
@ -564,11 +564,11 @@ def get_item_details(item, project = None):
frappe.throw(_("Default BOM for {0} not found").format(item))
bom_data = frappe.db.get_value('BOM', res['bom_no'],
['project', 'allow_alternative_item', 'transfer_material_against_job_card'], as_dict=1)
['project', 'allow_alternative_item', 'transfer_material_against'], as_dict=1)
res['project'] = project or bom_data.project
res['allow_alternative_item'] = bom_data.allow_alternative_item
res['transfer_material_against_job_card'] = bom_data.transfer_material_against_job_card
res['transfer_material_against'] = bom_data.transfer_material_against
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
return res
@ -682,7 +682,7 @@ def create_job_card(work_order, row, qty=0, auto_create=False):
'wip_warehouse': work_order.wip_warehouse
})
if work_order.transfer_material_against_job_card and not work_order.skip_transfer:
if work_order.transfer_material_against == 'Job Card' and not work_order.skip_transfer:
doc.get_required_items()
if auto_create:

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -342,7 +343,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_transfer_for_manufacture",
"fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -351,7 +352,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Transfer for Manufacture",
"label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -506,7 +507,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-10-04 16:16:54.237829",
"modified": "2018-11-20 19:04:38.508839",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order Item",

View File

@ -495,7 +495,7 @@ erpnext.patches.v10_0.set_b2c_limit
erpnext.patches.v10_0.update_translatable_fields
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
erpnext.patches.v10_0.add_default_cash_flow_mappers
erpnext.patches.v11_0.make_quality_inspection_template
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
@ -579,3 +579,4 @@ erpnext.patches.v10_0.update_user_image_in_employee
erpnext.patches.v11_0.update_delivery_trip_status
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
erpnext.patches.v11_0.set_missing_gst_hsn_code
erpnext.patches.v11_0.rename_bom_wo_fields

View File

@ -6,37 +6,36 @@ import frappe
def execute():
frappe.reload_doc("hr", "doctype", "daily_work_summary_group")
frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user")
if not frappe.db.table_exists('Daily Work Summary Group'):
frappe.reload_doc("hr", "doctype", "daily_work_summary_group")
frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user")
# check if Daily Work Summary Settings Company table exists
try:
frappe.db.sql('DESC `tabDaily Work Summary Settings Company`')
except Exception:
return
# check if Daily Work Summary Settings Company table exists
try:
frappe.db.sql('DESC `tabDaily Work Summary Settings Company`')
except Exception:
return
# get the previously saved settings
previous_setting = get_previous_setting()
if previous_setting["companies"]:
for d in previous_setting["companies"]:
users = frappe.get_list("Employee", dict(
company=d.company, user_id=("!=", " ")), "user_id as user")
if(len(users)):
# create new group entry for each company entry
new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group",
name="Daily Work Summary for " + d.company,
users=users,
send_emails_at=d.send_emails_at,
subject=previous_setting["subject"],
message=previous_setting["message"]))
new_group.flags.ignore_permissions = True
new_group.flags.ignore_validate = True
new_group.insert(ignore_if_duplicate = True)
frappe.delete_doc("Daily Work Summary Settings")
frappe.delete_doc("Daily Work Summary Settings Company")
# get the previously saved settings
previous_setting = get_previous_setting()
if previous_setting["companies"]:
for d in previous_setting["companies"]:
users = frappe.get_list("Employee", dict(
company=d.company, user_id=("!=", " ")), "user_id as user")
if(len(users)):
# create new group entry for each company entry
new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group",
name="Daily Work Summary for " + d.company,
users=users,
send_emails_at=d.send_emails_at,
subject=previous_setting["subject"],
message=previous_setting["message"]))
new_group.flags.ignore_permissions = True
new_group.flags.ignore_validate = True
new_group.insert(ignore_if_duplicate = True)
def get_setting_companies():
return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
frappe.delete_doc("DocType", "Daily Work Summary Settings")
frappe.delete_doc("DocType", "Daily Work Summary Settings Company")
def get_previous_setting():
@ -47,3 +46,6 @@ def get_previous_setting():
obj[field] = value
obj["companies"] = get_setting_companies()
return obj
def get_setting_companies():
return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)

View File

@ -0,0 +1,36 @@
# Copyright (c) 2018, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']:
if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'):
if doctype != 'Item':
frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype))
else:
frappe.reload_doc('stock', 'doctype', frappe.scrub(doctype))
rename_field(doctype, "allow_transfer_for_manufacture", "include_item_in_manufacturing")
if frappe.db.has_column('BOM', 'allow_same_item_multiple_times'):
frappe.db.sql(""" UPDATE tabBOM
SET
allow_same_item_multiple_times = 0
WHERE
trim(coalesce(allow_same_item_multiple_times, '')) = '' """)
for doctype in ['BOM', 'Work Order']:
frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype))
if frappe.db.has_column(doctype, 'transfer_material_against_job_card'):
frappe.db.sql(""" UPDATE `tab%s`
SET transfer_material_against = CASE WHEN
transfer_material_against_job_card = 1 then 'Job Card' Else 'Work Order' END
WHERE docstatus < 2""" % (doctype))
else:
frappe.db.sql(""" UPDATE `tab%s`
SET transfer_material_against = 'Work Order'
WHERE docstatus < 2""" % (doctype))

View File

@ -1,28 +1,60 @@
import frappe
from frappe.desk.form.linked_with import get_linked_doctypes
# Skips user permission check for doctypes where department link field was recently added
# https://github.com/frappe/erpnext/pull/14121
def execute():
user_permissions = frappe.get_all("User Permission",
filters=[['allow', '=', 'Department']],
fields=['name', 'skip_for_doctype'])
doctypes_to_skip = []
for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip',
'Attendance', 'Training Feedback', 'Training Result Employee',
'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee',
'Timesheet', 'Sales Person', 'Payroll Employee Detail']:
if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue
doctypes_to_skip.append(doctype)
doctypes_to_skip = []
frappe.reload_doctype('User Permission')
for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip',
'Attendance', 'Training Feedback', 'Training Result Employee',
'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee',
'Timesheet', 'Sales Person', 'Payroll Employee Detail']:
if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue
doctypes_to_skip.append(doctype)
user_permissions = frappe.get_all("User Permission",
filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]],
fields=['name', 'applicable_for'])
for perm in user_permissions:
skip_for_doctype = perm.get('skip_for_doctype')
user_permissions_to_delete = []
new_user_permissions_list = []
skip_for_doctype = skip_for_doctype.split('\n') + doctypes_to_skip
skip_for_doctype = set(skip_for_doctype) # to remove duplicates
skip_for_doctype = '\n'.join(skip_for_doctype) # convert back to string
for user_permission in user_permissions:
if user_permission.applicable_for:
# simply delete user permission record since it needs to be skipped.
user_permissions_to_delete.append(user_permission.name)
else:
# if applicable_for is `None` it means that user permission is applicable for every doctype
# to avoid this we need to create other user permission records and only skip the listed doctypes in this patch
linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys()
applicable_for_doctypes = list(set(linked_doctypes) - set(doctypes_to_skip))
frappe.set_value('User Permission', perm.name, 'skip_for_doctype', skip_for_doctype)
user_permissions_to_delete.append(user_permission.name)
for doctype in applicable_for_doctypes:
if doctype:
# Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes)
new_user_permissions_list.append((
frappe.generate_hash("", 10),
user_permission.user,
user_permission.allow,
user_permission.for_value,
doctype,
0
))
if new_user_permissions_list:
frappe.db.sql('''
INSERT INTO `tabUser Permission`
(`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`)
VALUES {}'''.format(', '.join(['%s'] * len(new_user_permissions_list))), # nosec
tuple(new_user_permissions_list)
)
if user_permissions_to_delete:
frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` IN ({})'.format( # nosec
','.join(['%s'] * len(user_permissions_to_delete))
), tuple(user_permissions_to_delete))

View File

@ -6,7 +6,7 @@ import frappe
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
frappe.db.sql(""" update `tabItem` set allow_transfer_for_manufacture = 1
frappe.db.sql(""" update `tabItem` set include_item_in_manufacturing = 1
where ifnull(is_stock_item, 0) = 1""")
for doctype in ['BOM Item', 'Work Order Item', 'BOM Explosion Item']:
@ -14,7 +14,7 @@ def execute():
frappe.db.sql(""" update `tab{0}` child, tabItem item
set
child.allow_transfer_for_manufacture = 1
child.include_item_in_manufacturing = 1
where
child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1
""".format(doctype))

View File

@ -16,7 +16,7 @@ from six import iteritems
class Project(Document):
def get_feed(self):
return '{0}: {1}'.format(_(self.status), self.project_name)
return '{0}: {1}'.format(_(self.status), frappe.safe_decode(self.project_name))
def onload(self):
"""Load project tasks for quick view"""
@ -76,7 +76,7 @@ class Project(Document):
def validate_project_name(self):
if self.get("__islocal") and frappe.db.exists("Project", self.project_name):
frappe.throw(_("Project {0} already exists").format(self.project_name))
frappe.throw(_("Project {0} already exists").format(frappe.safe_decode(self.project_name)))
def validate_dates(self):
if self.expected_start_date and self.expected_end_date:
@ -258,13 +258,13 @@ class Project(Document):
self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
def update_sales_amount(self):
total_sales_amount = frappe.db.sql("""select sum(base_grand_total)
total_sales_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Order` where project = %s and docstatus=1""", self.name)
self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0
def update_billed_amount(self):
total_billed_amount = frappe.db.sql("""select sum(base_grand_total)
total_billed_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Invoice` where project = %s and docstatus=1""", self.name)
self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0

View File

@ -97,6 +97,9 @@ erpnext.setup.slides_settings = [
if (!this.values.company_abbr) {
return false;
}
if (this.values.company_abbr.length > 5) {
return false;
}
return true;
}
},

View File

@ -237,7 +237,7 @@ $.extend(erpnext.utils, {
let unscrub_option = frappe.model.unscrub(option);
let user_permission = frappe.defaults.get_user_permissions();
if(user_permission && user_permission[unscrub_option]) {
return user_permission[unscrub_option]["docs"];
return user_permission[unscrub_option].map(perm => perm.doc);
} else {
return $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort();
}

View File

@ -1,85 +1,75 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Fichier des Ecritures Comptables [FEC]"] = {
"filters": [{
"fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
{
"fieldname": "fiscal_year",
"label": __("Fiscal Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"reqd": 1
}],
"filters": [
{
"fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company"),
"reqd": 1
},
{
"fieldname": "fiscal_year",
"label": __("Fiscal Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"reqd": 1
}
],
onload: function(query_report) {
query_report.page.add_inner_button(__("Export"), function() {
var fiscal_year = query_report.get_values().fiscal_year;
var company = query_report.get_values().company;
fec_export(query_report);
});
frappe.call({
method: "frappe.client.get_value",
args: {
'doctype': "Company",
'fieldname': ['siren_number'],
'filters': {
'name': company
}
},
callback: function(data) {
var company_data = data.message.siren_number;
if (company_data === null || company_data === undefined) {
frappe.msgprint(__("Please register the SIREN number in the company information file"))
} else {
frappe.call({
method: "frappe.client.get_value",
args: {
'doctype': "Fiscal Year",
'fieldname': ['year_end_date'],
'filters': {
'name': fiscal_year
}
},
callback: function(data) {
var fy = data.message.year_end_date;
var title = company_data + "FEC" + moment(fy).format('YYYYMMDD');
var result = $.map(frappe.slickgrid_tools.get_view_data(query_report.columns, query_report.dataView),
function(row) {
return [row.splice(1)];
});
downloadify(result, null, title);
}
});
query_report.add_make_chart_button = function() {
//
};
}
}
query_report.export_report = function() {
fec_export(query_report);
};
}
};
let fec_export = function(query_report) {
const fiscal_year = query_report.get_values().fiscal_year;
const company = query_report.get_values().company;
frappe.db.get_value("Company", company, "siren_number", (value) => {
const company_data = value.siren_number;
if (company_data === null || company_data === undefined) {
frappe.msgprint(__("Please register the SIREN number in the company information file"));
} else {
frappe.db.get_value("Fiscal Year", fiscal_year, "year_end_date", (r) => {
const fy = r.year_end_date;
const title = company_data + "FEC" + moment(fy).format('YYYYMMDD');
const column_row = query_report.columns.map(col => col.label);
const column_data = query_report.get_data_for_csv(false);
const result = [column_row].concat(column_data);
downloadify(result, null, title);
});
});
}
}
}
});
};
var downloadify = function(data, roles, title) {
let downloadify = function(data, roles, title) {
if (roles && roles.length && !has_common(roles, roles)) {
frappe.msgprint(__("Export not allowed. You need {0} role to export.", [frappe.utils.comma_or(roles)]));
return;
}
var filename = title + ".csv";
var csv_data = to_tab_csv(data);
var a = document.createElement('a');
const filename = title + ".txt";
let csv_data = to_tab_csv(data);
const a = document.createElement('a');
if ("download" in a) {
// Used Blob object, because it can handle large files
var blob_object = new Blob([csv_data], {
let blob_object = new Blob([csv_data], {
type: 'text/csv;charset=UTF-8'
});
a.href = URL.createObjectURL(blob_object);
@ -98,8 +88,8 @@ var downloadify = function(data, roles, title) {
document.body.removeChild(a);
};
var to_tab_csv = function(data) {
var res = [];
let to_tab_csv = function(data) {
let res = [];
$.each(data, function(i, row) {
res.push(row.join("\t"));
});

View File

@ -1,6 +1,11 @@
Selling management module. Includes forms for capturing / managing the sales process.
Selling management module. Includes forms for capturing / managing the sales process:
- Customer
- Campaign
- Quotation
- Sales Order
Moved to CRM Module:
- Lead
- Opportunity
- Quotation
- Sales Order

View File

@ -871,10 +871,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -993,6 +995,7 @@
"label": "Net Rate",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@ -1910,7 +1913,7 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
"modified": "2018-08-22 16:15:52.750381",
"modified": "2018-12-12 05:52:46.135944",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
@ -1925,4 +1928,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View File

@ -620,7 +620,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
def update_item(source, target, source_parent):
target.amount = flt(source.amount) - flt(source.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty
target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty - source.returned_qty
if source_parent.project:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")

View File

@ -394,7 +394,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
}
}
frappe.prompt(this.get_promopt_fields(),
frappe.prompt(this.get_prompt_fields(),
on_submit,
__('Select POS Profile')
);
@ -417,11 +417,12 @@ erpnext.pos.PointOfSale = class PointOfSale {
]);
}
get_promopt_fields() {
get_prompt_fields() {
return [{
fieldtype: 'Link',
label: __('POS Profile'),
options: 'POS Profile',
fieldname: 'pos_profile',
reqd: 1,
get_query: () => {
return {
@ -433,7 +434,8 @@ erpnext.pos.PointOfSale = class PointOfSale {
}
}, {
fieldtype: 'Check',
label: __('Set as default')
label: __('Set as default'),
fieldname: 'set_as_default'
}];
}
@ -522,6 +524,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
this.frm.meta.default_print_format = r.message.print_format || "";
this.frm.allow_edit_rate = r.message.allow_edit_rate;
this.frm.allow_edit_discount = r.message.allow_edit_discount;
this.frm.doc.campaign = r.message.campaign;
}
}
@ -1128,12 +1131,15 @@ class POSItems {
this.events = events;
this.currency = this.frm.doc.currency;
this.make_dom();
this.make_fields();
frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
this.parent_item_group = r.name;
this.make_dom();
this.make_fields();
this.init_clusterize();
this.bind_events();
this.load_items_data();
this.init_clusterize();
this.bind_events();
this.load_items_data();
})
}
load_items_data() {
@ -1175,6 +1181,7 @@ class POSItems {
make_fields() {
// Search field
const me = this;
this.search_field = frappe.ui.form.make_control({
df: {
fieldtype: 'Data',
@ -1202,7 +1209,7 @@ class POSItems {
fieldtype: 'Link',
label: 'Item Group',
options: 'Item Group',
default: 'All Item Groups',
default: me.parent_item_group,
onchange: () => {
const item_group = this.item_group_field.get_value();
if (item_group) {
@ -1258,7 +1265,7 @@ class POSItems {
this.clusterize.update(row_items);
}
filter_items({ search_term='', item_group='All Item Groups' }={}) {
filter_items({ search_term='', item_group=this.parent_item_group }={}) {
if (search_term) {
search_term = search_term.toLowerCase();
@ -1271,7 +1278,7 @@ class POSItems {
this.set_item_in_the_cart(items);
return;
}
} else if (item_group == "All Item Groups") {
} else if (item_group == this.parent_item_group) {
this.items = this.all_items;
return this.render_items(this.all_items);
}
@ -1376,7 +1383,7 @@ class POSItems {
return template;
}
get_items({start = 0, page_length = 40, search_value='', item_group="All Item Groups"}={}) {
get_items({start = 0, page_length = 40, search_value='', item_group=this.parent_item_group}={}) {
return new Promise(res => {
frappe.call({
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items",

View File

@ -0,0 +1,6 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Pending SO Items For Purchase Request"] = {
}

View File

@ -1,36 +1,35 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2013-06-21 16:46:45",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:08:11.744036",
"modified_by": "Administrator",
"module": "Selling",
"name": "Pending SO Items For Purchase Request",
"owner": "Administrator",
"query": "select so_item.item_code as \"Item Code:Link/Item:120\",\n so_item.item_name as \"Item Name::120\",\n so_item.description as \"Description::120\",\n so.`name` as \"S.O. No.:Link/Sales Order:120\",\n so.`transaction_date` as \"Date:Date:120\",\n mr.name as \"Material Request:Link/Material Request:120\",\n so.customer as \"Customer:Link/Customer:120\",\n so.territory as \"Terretory:Link/Territory:120\",\n sum(so_item.qty) as \"SO Qty:Float:100 \",\n sum(mr_item.qty) as \"Requested Qty:Float:100\",\n sum(so_item.qty) - sum(mr_item.qty) as \"Pending Qty:Float:100 \", \n so.company as \"Company:Link/Company:\"\nfrom\n `tabSales Order` so, `tabSales Order Item` so_item, \n `tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere \n so_item.`parent` = so.`name` \n and mr_item.parent = mr.name\n and mr_item.sales_order = so.name\n and mr_item.item_code = so_item.item_code\n and so.docstatus = 1 and so.status != \"Closed\" \n and mr.docstatus = 1 and mr.status != \"Stopped\"\ngroup by so.name, so_item.item_code\nhaving sum(so_item.qty) > sum(mr_item.qty)\norder by so.name desc, so_item.item_code asc",
"ref_doctype": "Sales Order",
"report_name": "Pending SO Items For Purchase Request",
"report_type": "Query Report",
"add_total_row": 0,
"creation": "2018-11-12 14:08:27.241332",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2018-11-12 14:08:27.241332",
"modified_by": "Administrator",
"module": "Selling",
"name": "Pending SO Items For Purchase Request",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Order",
"report_name": "Pending SO Items For Purchase Request",
"report_type": "Script Report",
"roles": [
{
"role": "Sales User"
},
"role": "Stock User"
},
{
"role": "Sales Manager"
},
},
{
"role": "Maintenance User"
},
},
{
"role": "Accounts User"
},
},
{
"role": "Stock User"
"role": "Sales User"
}
]
}

View File

@ -0,0 +1,148 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint,cstr
def execute(filters=None):
columns = get_columns()
data = get_data()
return columns, data
def get_columns():
columns = [
{
"label": _("Item Code"),
"options": "Item",
"fieldname": "item_code",
"fieldtype": "Link",
"width": 200
},
{
"label": _("Item Name"),
"fieldname": "item_name",
"fieldtype": "Data",
"width": 200
},
{
"label": _("Description"),
"fieldname": "description",
"fieldtype": "Data",
"width": 140
},
{
"label": _("S.O. No."),
"options": "Sales Order",
"fieldname": "sales_order_no",
"fieldtype": "Link",
"width": 140
},
{
"label": _("Date"),
"fieldname": "date",
"fieldtype": "Date",
"width": 140
},
{
"label": _("Material Request"),
"options": "Material Request",
"fieldname": "material_request",
"fieldtype": "Link",
"width": 140
},
{
"label": _("Customer"),
"fieldname": "customer",
"fieldtype": "Data",
"width": 140
},
{
"label": _("Territory"),
"fieldname": "territory",
"fieldtype": "Data",
"width": 140
},
{
"label": _("SO Qty"),
"fieldname": "so_qty",
"fieldtype": "Float",
"width": 140
},
{
"label": _("Requested Qty"),
"fieldname": "requested_qty",
"fieldtype": "Float",
"width": 140
},
{
"label": _("Pending Qty"),
"fieldname": "pending_qty",
"fieldtype": "Float",
"width": 140
},
{
"label": _("Company"),
"fieldname": "company",
"fieldtype": "Data",
"width": 140
}
]
return columns
def get_data():
sales_order_entry = frappe.db.sql("""
SELECT
so_item.item_code,
so_item.item_name,
so_item.description,
so.name,
so.transaction_date,
so.customer,
so.territory,
sum(so_item.qty) as net_qty,
so.company
FROM `tabSales Order` so, `tabSales Order Item` so_item
WHERE
so.docstatus = 1
and so.name = so_item.parent
and so.status not in ("Closed","Completed","Cancelled")
GROUP BY
so.name,so_item.item_code
""", as_dict = 1)
mr_records = frappe.get_all("Material Request Item",
{"sales_order_item": ("!=",""), "docstatus": 1},
["parent", "qty", "sales_order", "item_code"])
grouped_records = {}
for record in mr_records:
grouped_records.setdefault(record.sales_order, []).append(record)
pending_so=[]
for so in sales_order_entry:
# fetch all the material request records for a sales order item
mr_list = grouped_records.get(so.name) or [{}]
mr_item_record = ([mr for mr in mr_list if mr.get('item_code') == so.item_code] or [{}])
for mr in mr_item_record:
# check for pending sales order
if cint(so.net_qty) > cint(mr.get('qty')):
so_record = {
"item_code": so.item_code,
"item_name": so.item_name,
"description": so.description,
"sales_order_no": so.name,
"date": so.transaction_date,
"material_request": cstr(mr.get('parent')),
"customer": so.customer,
"territory": so.territory,
"so_qty": so.net_qty,
"requested_qty": cint(mr.get('qty')),
"pending_qty": so.net_qty - cint(mr.get('qty')),
"company": so.company
}
pending_so.append(so_record)
return pending_so

View File

@ -0,0 +1,27 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import unittest
from frappe.utils import nowdate, add_months
from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request\
import execute
from erpnext.selling.doctype.sales_order.sales_order import make_material_request
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
class TestPendingSOItemsForPurchaseRequest(unittest.TestCase):
def test_result_for_partial_material_request(self):
so = make_sales_order()
mr=make_material_request(so.name)
mr.items[0].qty = 4
mr.schedule_date = add_months(nowdate(),1)
mr.submit()
report = execute()
l = len(report[1])
self.assertEqual((so.items[0].qty - mr.items[0].qty), report[1][l-1]['pending_qty'])
def test_result_for_so_item(self):
so = make_sales_order()
report = execute()
l = len(report[1])
self.assertEqual(so.items[0].qty, report[1][l-1]['pending_qty'])

View File

@ -394,8 +394,24 @@ def get_invoiced_qty_map(delivery_note):
return invoiced_qty_map
def get_returned_qty_map(sales_orders):
"""returns a map: {so_detail: returned_qty}"""
returned_qty_map = {}
for name, returned_qty in frappe.get_all('Sales Order Item', fields = ["name", "returned_qty"],
filters = {'parent': ('in', sales_orders), 'docstatus': 1}, as_list=1):
if not returned_qty_map.get(name):
returned_qty_map[name] = 0
returned_qty_map[name] += returned_qty
return returned_qty_map
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
doc = frappe.get_doc('Delivery Note', source_name)
sales_orders = [d.against_sales_order for d in doc.items]
returned_qty_map = get_returned_qty_map(sales_orders)
invoiced_qty_map = get_invoiced_qty_map(source_name)
def set_missing_values(source, target):
@ -415,7 +431,9 @@ def make_sales_invoice(source_name, target_doc=None):
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
def update_item(source_doc, target_doc, source_parent):
target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
target_doc.qty = (source_doc.qty -
invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0))
if source_doc.serial_no and source_parent.per_billed > 0:
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
target_doc.qty, source_parent.name)

View File

@ -1,7 +1,8 @@
frappe.listview_settings['Delivery Note'] = {
add_fields: ["grand_total", "is_return", "per_billed", "status", "currency"],
get_indicator: function (doc) {
if (cint(doc.is_return) == 1) {
add_fields: ["customer", "customer_name", "base_grand_total", "per_installed", "per_billed",
"transporter_name", "grand_total", "is_return", "status", "currency"],
get_indicator: function(doc) {
if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];

View File

@ -636,6 +636,24 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
set_perpetual_inventory(0, company)
def test_make_sales_invoice_from_dn_for_returned_qty(self):
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
so = make_sales_order(qty=2)
so.submit()
dn = make_delivery_note(so.name)
dn.submit()
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-1, do_not_submit=True)
dn1.items[0].against_sales_order = so.name
dn1.items[0].so_detail = so.items[0].name
dn1.submit()
si = make_sales_invoice(dn.name)
self.assertEquals(si.items[0].qty, 1)
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")

View File

@ -445,38 +445,38 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "allow_transfer_for_manufacture",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Transfer for Manufacture",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -4350,4 +4350,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View File

@ -395,4 +395,3 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None,
"company": "_Test Company"
})
item.save()

View File

@ -1,463 +1,464 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-05-03 02:29:24.444341",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-05-03 02:29:24.444341",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Default Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Default Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Default Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Default Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "purchase_defaults",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Purchase Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "purchase_defaults",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Purchase Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "buying_cost_center",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Buying Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "buying_cost_center",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Buying Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Supplier",
"length": 0,
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Supplier",
"length": 0,
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_8",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_8",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Expense Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "expense_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Expense Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "selling_defaults",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Sales Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "selling_defaults",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Sales Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "selling_cost_center",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Selling Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "selling_cost_center",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Selling Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "income_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Income Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "income_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Income Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-09-19 16:17:52.562232",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Default",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-12-07 11:48:07.638935",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Default",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}

View File

@ -456,31 +456,40 @@ def raise_work_orders(material_request):
errors =[]
work_orders = []
default_wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
for d in mr.items:
if (d.qty - d.ordered_qty) >0:
if frappe.db.get_value("BOM", {"item": d.item_code, "is_default": 1}):
if frappe.db.exists("BOM", {"item": d.item_code, "is_default": 1}):
wo_order = frappe.new_doc("Work Order")
wo_order.production_item = d.item_code
wo_order.qty = d.qty - d.ordered_qty
wo_order.fg_warehouse = d.warehouse
wo_order.wip_warehouse = default_wip_warehouse
wo_order.description = d.description
wo_order.stock_uom = d.stock_uom
wo_order.expected_delivery_date = d.schedule_date
wo_order.sales_order = d.sales_order
wo_order.bom_no = get_item_details(d.item_code).bom_no
wo_order.material_request = mr.name
wo_order.material_request_item = d.name
wo_order.planned_start_date = mr.transaction_date
wo_order.company = mr.company
wo_order.update({
"production_item": d.item_code,
"qty": d.qty - d.ordered_qty,
"fg_warehouse": d.warehouse,
"wip_warehouse": default_wip_warehouse,
"description": d.description,
"stock_uom": d.stock_uom,
"expected_delivery_date": d.schedule_date,
"sales_order": d.sales_order,
"bom_no": get_item_details(d.item_code).bom_no,
"material_request": mr.name,
"material_request_item": d.name,
"planned_start_date": mr.transaction_date,
"company": mr.company
})
wo_order.set_work_order_operations()
wo_order.save()
work_orders.append(wo_order.name)
else:
errors.append(_("Row {0}: Bill of Materials not found for the Item {1}").format(d.idx, d.item_code))
if work_orders:
message = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in work_orders]
msgprint(_("The following Work Orders were created:") + '\n' + new_line_sep(message))
if errors:
frappe.throw(_("Productions Orders cannot be raised for:") + '\n' + new_line_sep(errors))
return work_orders

View File

@ -1,7 +1,8 @@
frappe.listview_settings['Purchase Receipt'] = {
add_fields: ["is_return", "grand_total", "status", "per_billed"],
get_indicator: function (doc) {
if (cint(doc.is_return) == 1) {
add_fields: ["supplier", "supplier_name", "base_grand_total", "is_subcontracted",
"transporter_name", "is_return", "status", "per_billed", "currency"],
get_indicator: function(doc) {
if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];

View File

@ -3,8 +3,45 @@
import frappe
import unittest
from frappe.utils import nowdate
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError
# test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(unittest.TestCase):
pass
def setUp(self):
create_item("_Test Item with QA")
frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1)
def test_qa_for_delivery(self):
dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
self.assertRaises(QualityInspectionRequiredError, dn.submit)
qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
dn.reload()
self.assertRaises(QualityInspectionRejectedError, dn.submit)
frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
dn.reload()
dn.submit()
def create_quality_inspection(**args):
args = frappe._dict(args)
qa = frappe.new_doc("Quality Inspection")
qa.report_date = nowdate()
qa.inspection_type = args.inspection_type or "Outgoing"
qa.reference_type = args.reference_type
qa.reference_name = args.reference_name
qa.item_code = args.item_code or "_Test Item with QA"
qa.sample_size = 1
qa.inspected_by = frappe.session.user
qa.append("readings", {
"specification": "Size",
"status": args.status
})
qa.save()
qa.submit()
return qa

View File

@ -609,7 +609,7 @@ class StockEntry(StockController):
if self.job_card:
job_doc = frappe.get_doc('Job Card', self.job_card)
job_doc.set_transferred_qty()
job_doc.set_transferred_qty(update_status=True)
if self.work_order:
pro_doc = frappe.get_doc("Work Order", self.work_order)
@ -1003,7 +1003,7 @@ class StockEntry(StockController):
for d in pro_order.get("required_items"):
if (flt(d.required_qty) > flt(d.transferred_qty) and
(d.allow_transfer_for_manufacture or self.purpose != "Material Transfer for Manufacture")):
(d.include_item_in_manufacturing or self.purpose != "Material Transfer for Manufacture")):
item_row = d.as_dict()
if d.source_warehouse and not frappe.db.get_value("Warehouse", d.source_warehouse, "is_group"):
item_row["from_warehouse"] = d.source_warehouse

View File

@ -42,7 +42,7 @@ frappe.ui.form.on("Stock Reconciliation", {
},
get_items: function(frm) {
frappe.prompt({label:"Warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1,
frappe.prompt({label:"Warehouse", fieldname: "warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1,
"get_query": function() {
return {
"filters": {

View File

@ -10,7 +10,7 @@ frappe.query_reports["Warehouse wise Item Balance Age and Value"] = {
"fieldtype": "Date",
"width": "80",
"reqd": 1,
"default": frappe.sys_defaults.year_start_date,
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
},
{
"fieldname":"to_date",

View File

@ -8,7 +8,8 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, cint, getdate
from erpnext.stock.report.stock_balance.stock_balance import get_item_details, get_item_reorder_details, get_item_warehouse_map
from erpnext.stock.report.stock_balance.stock_balance import (get_item_details,
get_item_reorder_details, get_item_warehouse_map, get_items, get_stock_ledger_entries)
from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
from six import iteritems
@ -18,8 +19,12 @@ def execute(filters=None):
validate_filters(filters)
columns = get_columns(filters)
item_map = get_item_details(filters)
iwb_map = get_item_warehouse_map(filters)
items = get_items(filters)
sle = get_stock_ledger_entries(filters, items)
item_map = get_item_details(items, sle, filters)
iwb_map = get_item_warehouse_map(filters, sle)
warehouse_list = get_warehouse_list(filters)
item_ageing = get_fifo_queue(filters)
data = []
@ -27,6 +32,8 @@ def execute(filters=None):
item_value = {}
for (company, item, warehouse) in sorted(iwb_map):
if not item_map.get(item): continue
row = []
qty_dict = iwb_map[(company, item, warehouse)]
item_balance.setdefault((item, item_map[item]["item_group"]), [])
@ -42,6 +49,8 @@ def execute(filters=None):
# sum bal_qty by item
for (item, item_group), wh_balance in iteritems(item_balance):
if not item_ageing.get(item): continue
total_stock_value = sum(item_value[(item, item_group)])
row = [item, item_group, total_stock_value]
@ -85,11 +94,10 @@ def validate_filters(filters):
filters["company"] = frappe.defaults.get_user_default("Company")
def get_warehouse_list(filters):
from frappe.defaults import get_user_permissions
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
condition = ''
user_permitted_warehouse = filter(None, get_user_permissions()
.get("Warehouse", {})
.get("docs", []))
user_permitted_warehouse = get_permitted_documents('Warehouse')
value = ()
if user_permitted_warehouse:
condition = "and name in %s"

View File

@ -16,7 +16,7 @@
<tr>
<td>{{ item }}</td>
<td class='text-right'>
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
{{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }}
</td>
{% for tax_account in tax_accounts %}
{% set tax_details = taxes.get(tax_account) %}