Merge branch 'staging-fixes' of https://github.com/frappe/erpnext into stock-recon
This commit is contained in:
commit
9eb99dc61e
@ -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'''
|
||||
|
@ -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]
|
||||
|
@ -108,33 +108,33 @@ def get_conditions(filters):
|
||||
def get_pos_invoice_data(filters):
|
||||
conditions = get_conditions(filters)
|
||||
result = frappe.db.sql(''
|
||||
'SELECT '
|
||||
'posting_date, owner, sum(net_total) as "net_total", sum(total_taxes) as "total_taxes", '
|
||||
'sum(paid_amount) as "paid_amount", sum(outstanding_amount) as "outstanding_amount", '
|
||||
'mode_of_payment, warehouse, cost_center '
|
||||
'FROM ('
|
||||
'SELECT '
|
||||
'parent, item_code, sum(amount) as "base_total", warehouse, cost_center '
|
||||
'from `tabSales Invoice Item` group by parent'
|
||||
') t1 '
|
||||
'left join '
|
||||
'(select parent, mode_of_payment from `tabSales Invoice Payment` group by parent) t3 '
|
||||
'on (t3.parent = t1.parent) '
|
||||
'JOIN ('
|
||||
'SELECT '
|
||||
'docstatus, company, is_pos, name, posting_date, owner, sum(base_total) as "base_total", '
|
||||
'sum(net_total) as "net_total", sum(total_taxes_and_charges) as "total_taxes", '
|
||||
'sum(base_paid_amount) as "paid_amount", sum(outstanding_amount) as "outstanding_amount" '
|
||||
'FROM `tabSales Invoice` '
|
||||
'GROUP BY name'
|
||||
') a '
|
||||
'ON ('
|
||||
't1.parent = a.name and t1.base_total = a.base_total) '
|
||||
'WHERE a.docstatus = 1'
|
||||
' AND {conditions} '
|
||||
'GROUP BY '
|
||||
'owner, posting_date, warehouse'.format(conditions=conditions), filters, as_dict=1
|
||||
)
|
||||
'SELECT '
|
||||
'posting_date, owner, sum(net_total) as "net_total", sum(total_taxes) as "total_taxes", '
|
||||
'sum(paid_amount) as "paid_amount", sum(outstanding_amount) as "outstanding_amount", '
|
||||
'mode_of_payment, warehouse, cost_center '
|
||||
'FROM ('
|
||||
'SELECT '
|
||||
'parent, item_code, sum(amount) as "base_total", warehouse, cost_center '
|
||||
'from `tabSales Invoice Item` group by parent'
|
||||
') t1 '
|
||||
'left join '
|
||||
'(select parent, mode_of_payment from `tabSales Invoice Payment` group by parent) t3 '
|
||||
'on (t3.parent = t1.parent) '
|
||||
'JOIN ('
|
||||
'SELECT '
|
||||
'docstatus, company, is_pos, name, posting_date, owner, sum(base_total) as "base_total", '
|
||||
'sum(net_total) as "net_total", sum(total_taxes_and_charges) as "total_taxes", '
|
||||
'sum(base_paid_amount) as "paid_amount", sum(outstanding_amount) as "outstanding_amount" '
|
||||
'FROM `tabSales Invoice` '
|
||||
'GROUP BY name'
|
||||
') a '
|
||||
'ON ('
|
||||
't1.parent = a.name and t1.base_total = a.base_total) '
|
||||
'WHERE a.docstatus = 1'
|
||||
' AND {conditions} '
|
||||
'GROUP BY '
|
||||
'owner, posting_date, warehouse'.format(conditions=conditions), filters, as_dict=1
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@ -156,7 +156,6 @@ def get_sales_invoice_data(filters):
|
||||
|
||||
|
||||
def get_mode_of_payments(filters):
|
||||
frappe.log_error(filters, 'filters')
|
||||
mode_of_payments = {}
|
||||
invoice_list = get_invoices(filters)
|
||||
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
|
||||
@ -164,12 +163,14 @@ def get_mode_of_payments(filters):
|
||||
inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
|
||||
from `tabSales Invoice` a, `tabSales Invoice Payment` b
|
||||
where a.name = b.parent
|
||||
and a.docstatus = 1
|
||||
and a.name in ({invoice_list_names})
|
||||
union
|
||||
select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
|
||||
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
|
||||
where a.name = c.reference_name
|
||||
and b.name = c.parent
|
||||
and b.docstatus = 1
|
||||
and a.name in ({invoice_list_names})
|
||||
union
|
||||
select a.owner, a.posting_date,
|
||||
@ -196,13 +197,13 @@ def get_invoices(filters):
|
||||
def get_mode_of_payment_details(filters):
|
||||
mode_of_payment_details = {}
|
||||
invoice_list = get_invoices(filters)
|
||||
frappe.log_error(invoice_list, 'invoice_list')
|
||||
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
|
||||
if invoice_list:
|
||||
inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date,
|
||||
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount
|
||||
from `tabSales Invoice` a, `tabSales Invoice Payment` b
|
||||
where a.name = b.parent
|
||||
and a.docstatus = 1
|
||||
and a.name in ({invoice_list_names})
|
||||
group by a.owner, a.posting_date, mode_of_payment
|
||||
union
|
||||
@ -211,6 +212,7 @@ def get_mode_of_payment_details(filters):
|
||||
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
|
||||
where a.name = c.reference_name
|
||||
and b.name = c.parent
|
||||
and b.docstatus = 1
|
||||
and a.name in ({invoice_list_names})
|
||||
group by a.owner, a.posting_date, mode_of_payment
|
||||
union
|
||||
|
@ -0,0 +1,165 @@
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import frappe
|
||||
from erpnext.accounts.report.sales_payment_summary.sales_payment_summary import get_mode_of_payments, get_mode_of_payment_details
|
||||
from frappe.utils import today
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
|
||||
test_dependencies = ["Sales Invoice"]
|
||||
|
||||
class TestSalesPaymentSummary(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
create_records()
|
||||
pes = frappe.get_all("Payment Entry")
|
||||
jes = frappe.get_all("Journal Entry")
|
||||
sis = frappe.get_all("Sales Invoice")
|
||||
for pe in pes:
|
||||
frappe.db.set_value("Payment Entry", pe.name, "docstatus", 2)
|
||||
for je in jes:
|
||||
frappe.db.set_value("Journal Entry", je.name, "docstatus", 2)
|
||||
for si in sis:
|
||||
frappe.db.set_value("Sales Invoice", si.name, "docstatus", 2)
|
||||
|
||||
def test_get_mode_of_payments(self):
|
||||
filters = get_filters()
|
||||
|
||||
for dummy in range(2):
|
||||
si = create_sales_invoice_record()
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
if int(si.name[-3:])%2 == 0:
|
||||
bank_account = "_Test Cash - _TC"
|
||||
mode_of_payment = "Cash"
|
||||
else:
|
||||
bank_account = "_Test Bank - _TC"
|
||||
mode_of_payment = "Credit Card"
|
||||
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account=bank_account)
|
||||
pe.reference_no = "_Test"
|
||||
pe.reference_date = today()
|
||||
pe.mode_of_payment = mode_of_payment
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
mop = get_mode_of_payments(filters)
|
||||
self.assertTrue('Credit Card' in mop.values()[0])
|
||||
self.assertTrue('Cash' in mop.values()[0])
|
||||
|
||||
# Cancel all Cash payment entry and check if this mode of payment is still fetched.
|
||||
payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Cash", "docstatus": 1}, fields=["name", "docstatus"])
|
||||
for payment_entry in payment_entries:
|
||||
pe = frappe.get_doc("Payment Entry", payment_entry.name)
|
||||
pe.cancel()
|
||||
|
||||
mop = get_mode_of_payments(filters)
|
||||
self.assertTrue('Credit Card' in mop.values()[0])
|
||||
self.assertTrue('Cash' not in mop.values()[0])
|
||||
|
||||
def test_get_mode_of_payments_details(self):
|
||||
filters = get_filters()
|
||||
|
||||
for dummy in range(2):
|
||||
si = create_sales_invoice_record()
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
if int(si.name[-3:])%2 == 0:
|
||||
bank_account = "_Test Cash - _TC"
|
||||
mode_of_payment = "Cash"
|
||||
else:
|
||||
bank_account = "_Test Bank - _TC"
|
||||
mode_of_payment = "Credit Card"
|
||||
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account=bank_account)
|
||||
pe.reference_no = "_Test"
|
||||
pe.reference_date = today()
|
||||
pe.mode_of_payment = mode_of_payment
|
||||
pe.insert()
|
||||
pe.submit()
|
||||
|
||||
mopd = get_mode_of_payment_details(filters)
|
||||
|
||||
mopd_values = mopd.values()[0]
|
||||
for mopd_value in mopd_values:
|
||||
if mopd_value[0] == "Credit Card":
|
||||
cc_init_amount = mopd_value[1]
|
||||
|
||||
# Cancel one Credit Card Payment Entry and check that it is not fetched in mode of payment details.
|
||||
payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Credit Card", "docstatus": 1}, fields=["name", "docstatus"])
|
||||
for payment_entry in payment_entries[:1]:
|
||||
pe = frappe.get_doc("Payment Entry", payment_entry.name)
|
||||
pe.cancel()
|
||||
|
||||
mopd = get_mode_of_payment_details(filters)
|
||||
mopd_values = mopd.values()[0]
|
||||
for mopd_value in mopd_values:
|
||||
if mopd_value[0] == "Credit Card":
|
||||
cc_final_amount = mopd_value[1]
|
||||
|
||||
self.assertTrue(cc_init_amount > cc_final_amount)
|
||||
|
||||
def get_filters():
|
||||
return {
|
||||
"from_date": "1900-01-01",
|
||||
"to_date": today(),
|
||||
"company": "_Test Company"
|
||||
}
|
||||
|
||||
def create_sales_invoice_record(qty=1):
|
||||
# return sales invoice doc object
|
||||
return frappe.get_doc({
|
||||
"doctype": "Sales Invoice",
|
||||
"customer": frappe.get_doc('Customer', {"customer_name": "Prestiga-Biz"}).name,
|
||||
"company": '_Test Company',
|
||||
"due_date": today(),
|
||||
"posting_date": today(),
|
||||
"currency": "INR",
|
||||
"taxes_and_charges": "",
|
||||
"debit_to": "Debtors - _TC",
|
||||
"taxes": [],
|
||||
"items": [{
|
||||
'doctype': 'Sales Invoice Item',
|
||||
'item_code': frappe.get_doc('Item', {'item_name': 'Consulting'}).name,
|
||||
'qty': qty,
|
||||
"rate": 10000,
|
||||
'income_account': 'Sales - _TC',
|
||||
'cost_center': 'Main - _TC',
|
||||
'expense_account': 'Cost of Goods Sold - _TC'
|
||||
}]
|
||||
})
|
||||
|
||||
def create_records():
|
||||
if frappe.db.exists("Customer", "Prestiga-Biz"):
|
||||
return
|
||||
|
||||
#customer
|
||||
frappe.get_doc({
|
||||
"customer_group": "_Test Customer Group",
|
||||
"customer_name": "Prestiga-Biz",
|
||||
"customer_type": "Company",
|
||||
"doctype": "Customer",
|
||||
"territory": "_Test Territory"
|
||||
}).insert()
|
||||
|
||||
# item
|
||||
item = frappe.get_doc({
|
||||
"doctype": "Item",
|
||||
"item_code": "Consulting",
|
||||
"item_name": "Consulting",
|
||||
"item_group": "All Item Groups",
|
||||
"company": "_Test Company",
|
||||
"is_stock_item": 0
|
||||
}).insert()
|
||||
|
||||
# item price
|
||||
frappe.get_doc({
|
||||
"doctype": "Item Price",
|
||||
"price_list": "Standard Selling",
|
||||
"item_code": item.item_code,
|
||||
"price_list_rate": 10000
|
||||
}).insert()
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
||||
|
@ -13,8 +13,8 @@ from frappe.model.document import Document
|
||||
from erpnext.utilities.transaction_base import delete_events
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
|
||||
class EmployeeUserDisabledError(frappe.ValidationError):
|
||||
pass
|
||||
class EmployeeUserDisabledError(frappe.ValidationError): pass
|
||||
class EmployeeLeftValidationError(frappe.ValidationError): pass
|
||||
|
||||
class Employee(NestedSet):
|
||||
nsm_parent_field = 'reports_to'
|
||||
@ -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()
|
||||
|
||||
@ -147,8 +147,16 @@ class Employee(NestedSet):
|
||||
validate_email_add(self.personal_email, True)
|
||||
|
||||
def validate_status(self):
|
||||
if self.status == 'Left' and not self.relieving_date:
|
||||
throw(_("Please enter relieving date."))
|
||||
if self.status == 'Left':
|
||||
reports_to = frappe.db.get_all('Employee',
|
||||
filters={'reports_to': self.name}
|
||||
)
|
||||
if reports_to:
|
||||
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
|
||||
throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
|
||||
+ ', '.join(link_to_employees), EmployeeLeftValidationError)
|
||||
if not self.relieving_date:
|
||||
throw(_("Please enter relieving date."))
|
||||
|
||||
def validate_for_enabled_user_id(self, enabled):
|
||||
if not self.status == 'Active':
|
||||
|
@ -7,6 +7,7 @@ import frappe
|
||||
import erpnext
|
||||
import unittest
|
||||
import frappe.utils
|
||||
from erpnext.hr.doctype.employee.employee import EmployeeLeftValidationError
|
||||
|
||||
test_records = frappe.get_test_records('Employee')
|
||||
|
||||
@ -32,6 +33,18 @@ class TestEmployee(unittest.TestCase):
|
||||
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
|
||||
self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message)
|
||||
|
||||
def test_employee_status_left(self):
|
||||
employee1 = make_employee("test_employee_1@company.com")
|
||||
employee2 = make_employee("test_employee_2@company.com")
|
||||
employee1_doc = frappe.get_doc("Employee", employee1)
|
||||
employee2_doc = frappe.get_doc("Employee", employee2)
|
||||
employee2_doc.reload()
|
||||
employee2_doc.reports_to = employee1_doc.name
|
||||
employee2_doc.save()
|
||||
employee1_doc.reload()
|
||||
employee1_doc.status = 'Left'
|
||||
self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
|
||||
|
||||
def make_employee(user):
|
||||
if not frappe.db.get_value("User", user):
|
||||
frappe.get_doc({
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from frappe.utils import getdate
|
||||
from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
|
||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||
|
||||
class TestUploadAttendance(unittest.TestCase):
|
||||
def test_date_range(self):
|
||||
employee = make_employee("test_employee@company.com")
|
||||
employee_doc = frappe.get_doc("Employee", employee)
|
||||
date_of_joining = "2018-01-02"
|
||||
relieving_date = "2018-01-03"
|
||||
from_date = "2018-01-01"
|
||||
to_date = "2018-01-04"
|
||||
employee_doc.date_of_joining = date_of_joining
|
||||
employee_doc.relieving_date = relieving_date
|
||||
employee_doc.save()
|
||||
args = {
|
||||
"from_date": from_date,
|
||||
"to_date": to_date
|
||||
}
|
||||
data = get_data(args)
|
||||
filtered_data = []
|
||||
for row in data:
|
||||
if row[1] == employee:
|
||||
filtered_data.append(row)
|
||||
print(filtered_data)
|
||||
for row in filtered_data:
|
||||
self.assertTrue(getdate(row[3]) >= getdate(date_of_joining) and getdate(row[3]) <= getdate(relieving_date))
|
@ -41,16 +41,28 @@ def add_header(w):
|
||||
return w
|
||||
|
||||
def add_data(w, args):
|
||||
data = get_data(args)
|
||||
writedata(w, data)
|
||||
return w
|
||||
|
||||
def get_data(args):
|
||||
dates = get_dates(args)
|
||||
employees = get_active_employees()
|
||||
existing_attendance_records = get_existing_attendance_records(args)
|
||||
data = []
|
||||
for date in dates:
|
||||
for employee in employees:
|
||||
if getdate(date) < getdate(employee.date_of_joining):
|
||||
continue
|
||||
if employee.relieving_date:
|
||||
if getdate(date) > getdate(employee.relieving_date):
|
||||
continue
|
||||
existing_attendance = {}
|
||||
if existing_attendance_records \
|
||||
and tuple([getdate(date), employee.name]) in existing_attendance_records:
|
||||
and tuple([getdate(date), employee.name]) in existing_attendance_records \
|
||||
and getdate(employee.date_of_joining) >= getdate(date) \
|
||||
and getdate(employee.relieving_date) <= getdate(date):
|
||||
existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
|
||||
|
||||
row = [
|
||||
existing_attendance and existing_attendance.name or "",
|
||||
employee.name, employee.employee_name, date,
|
||||
@ -58,8 +70,12 @@ def add_data(w, args):
|
||||
existing_attendance and existing_attendance.leave_type or "", employee.company,
|
||||
existing_attendance and existing_attendance.naming_series or get_naming_series(),
|
||||
]
|
||||
w.writerow(row)
|
||||
return w
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
def writedata(w, data):
|
||||
for row in data:
|
||||
w.writerow(row)
|
||||
|
||||
def get_dates(args):
|
||||
"""get list of dates in between from date and to date"""
|
||||
@ -68,8 +84,13 @@ def get_dates(args):
|
||||
return dates
|
||||
|
||||
def get_active_employees():
|
||||
employees = frappe.db.sql("""select name, employee_name, company
|
||||
from tabEmployee where docstatus < 2 and status = 'Active'""", as_dict=1)
|
||||
employees = frappe.db.get_all('Employee',
|
||||
fields=['name', 'employee_name', 'date_of_joining', 'company', 'relieving_date'],
|
||||
filters={
|
||||
'docstatus': ['<', 2],
|
||||
'status': 'Active'
|
||||
}
|
||||
)
|
||||
return employees
|
||||
|
||||
def get_existing_attendance_records(args):
|
||||
|
@ -79,67 +79,67 @@
|
||||
"unique": 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,
|
||||
"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,
|
||||
"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
|
||||
},
|
||||
{
|
||||
@ -966,6 +966,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "item_code.include_item_in_manufacturing",
|
||||
"fieldname": "include_item_in_manufacturing",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@ -974,6 +975,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Include Item In Manufacturing",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@ -987,29 +989,6 @@
|
||||
"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
|
||||
},
|
||||
{
|
||||
@ -1044,71 +1023,6 @@
|
||||
"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": "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": "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,
|
||||
@ -1121,7 +1035,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-11-22 15:04:55.187136",
|
||||
"modified": "2018-12-28 16:38:56.529079",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Item",
|
||||
|
@ -8,7 +8,19 @@ 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'):
|
||||
rename_field('BOM Item', "allow_transfer_for_manufacture", "include_item_in_manufacturing")
|
||||
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))
|
||||
|
@ -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))
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
},
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +623,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")
|
||||
|
@ -391,8 +391,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):
|
||||
@ -412,7 +428,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)
|
||||
|
@ -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"];
|
||||
|
@ -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")
|
||||
|
@ -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"];
|
||||
|
@ -94,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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user