Merge branch 'develop' of https://github.com/frappe/erpnext into develop
This commit is contained in:
commit
6ee4c09854
@ -1,3 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://test_site_ui:8000"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
context('Form', () => {
|
||||
before(() => {
|
||||
cy.login('Administrator', 'qwe');
|
||||
cy.visit('/desk');
|
||||
});
|
||||
|
||||
it('create a new opportunity', () => {
|
||||
cy.visit('/desk#Form/Opportunity/New Opportunity 1');
|
||||
cy.get('.page-title').should('contain', 'Not Saved');
|
||||
cy.fill_field('opportunity_from', 'Customer', 'Select');
|
||||
cy.fill_field('party_name', 'Test Customer', 'Link').blur();
|
||||
cy.get('.primary-action').click();
|
||||
cy.get('.page-title').should('contain', 'Open');
|
||||
cy.get('.form-inner-toolbar button:contains("Lost")').click({ force: true });
|
||||
cy.get('.modal input[data-fieldname="lost_reason"]').as('input');
|
||||
cy.get('@input').focus().type('Higher', { delay: 200 });
|
||||
cy.get('.modal .awesomplete ul')
|
||||
.should('be.visible')
|
||||
.get('li:contains("Higher Price")')
|
||||
.click({ force: true });
|
||||
cy.get('@input').focus().type('No Followup', { delay: 200 });
|
||||
cy.get('.modal .awesomplete ul')
|
||||
.should('be.visible')
|
||||
.get('li:contains("No Followup")')
|
||||
.click();
|
||||
|
||||
cy.fill_field('detailed_reason', 'Test Detailed Reason', 'Text');
|
||||
cy.get('.modal button:contains("Declare Lost")').click({ force: true });
|
||||
cy.get('.page-title').should('contain', 'Lost');
|
||||
});
|
||||
});
|
@ -1,17 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
// module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
// }
|
@ -1,25 +0,0 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
@ -1,22 +0,0 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// import frappe commands
|
||||
import '../../../frappe/cypress/support/index';
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-24 19:29:05",
|
||||
@ -373,7 +372,8 @@
|
||||
"no_copy": 1,
|
||||
"options": "Sales Invoice",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_21",
|
||||
@ -1568,8 +1568,7 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 181,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:15:59.580414",
|
||||
"modified": "2020-02-10 04:57:11.221180",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -10,7 +10,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
|
||||
|
||||
def post_depreciation_entries(date=None):
|
||||
# Return if automatic booking of asset depreciation is disabled
|
||||
if not cint(frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")):
|
||||
if not cint(frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")):
|
||||
return
|
||||
|
||||
if not date:
|
||||
|
@ -47,7 +47,7 @@ class ProductionPlan(Document):
|
||||
'sales_order': data.name,
|
||||
'sales_order_date': data.transaction_date,
|
||||
'customer': data.customer,
|
||||
'grand_total': data.grand_total
|
||||
'grand_total': data.base_grand_total
|
||||
})
|
||||
|
||||
def get_pending_material_requests(self):
|
||||
|
@ -90,7 +90,8 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
args: {
|
||||
qty: qty,
|
||||
item_code: me.item_code,
|
||||
warehouse: me.warehouse_details.name
|
||||
warehouse: me.warehouse_details.name,
|
||||
batch_no: me.item.batch_no || null
|
||||
}
|
||||
});
|
||||
|
||||
@ -392,7 +393,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
delivery_document_no: ""
|
||||
}
|
||||
|
||||
if (this.has_batch) {
|
||||
if (this.item.batch_no) {
|
||||
serial_no_filters["batch_no"] = this.item.batch_no;
|
||||
}
|
||||
|
||||
|
@ -158,8 +158,11 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
def test_purchase_return_for_rejected_qty(self):
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
|
||||
|
||||
rejected_warehouse=get_warehouse(company = "_Test Company with perpetual inventory", abbr = " - TCP1", warehouse_name = "_Test Rejected Warehouse").name
|
||||
print(rejected_warehouse)
|
||||
rejected_warehouse="_Test Rejected Warehouse - TCP1"
|
||||
if not frappe.db.exists("Warehouse", rejected_warehouse):
|
||||
get_warehouse(company = "_Test Company with perpetual inventory",
|
||||
abbr = " - TCP1", warehouse_name = "_Test Rejected Warehouse").name
|
||||
|
||||
pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", received_qty=4, qty=2, rejected_warehouse=rejected_warehouse)
|
||||
|
||||
return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, received_qty = -4, qty=-2, rejected_warehouse=rejected_warehouse)
|
||||
@ -262,6 +265,31 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
self.assertEqual(pr2.per_billed, 80)
|
||||
self.assertEqual(pr2.status, "To Bill")
|
||||
|
||||
def test_serial_no_against_purchase_receipt(self):
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
item_code = "Test Manual Created Serial No"
|
||||
if not frappe.db.exists("Item", item_code):
|
||||
item = make_item(item_code, dict(has_serial_no=1))
|
||||
|
||||
serial_no = "12903812901"
|
||||
pr_doc = make_purchase_receipt(item_code=item_code,
|
||||
qty=1, serial_no = serial_no)
|
||||
|
||||
self.assertEqual(serial_no, frappe.db.get_value("Serial No",
|
||||
{"purchase_document_type": "Purchase Receipt", "purchase_document_no": pr_doc.name}, "name"))
|
||||
|
||||
#check for the auto created serial nos
|
||||
item_code = "Test Auto Created Serial No"
|
||||
if not frappe.db.exists("Item", item_code):
|
||||
item = make_item(item_code, dict(has_serial_no=1, serial_no_series="KLJL.###"))
|
||||
|
||||
new_pr_doc = make_purchase_receipt(item_code=item_code, qty=1)
|
||||
|
||||
serial_no = get_serial_nos(new_pr_doc.items[0].serial_no)[0]
|
||||
self.assertEqual(serial_no, frappe.db.get_value("Serial No",
|
||||
{"purchase_document_type": "Purchase Receipt", "purchase_document_no": new_pr_doc.name}, "name"))
|
||||
|
||||
def test_not_accept_duplicate_serial_no(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
|
@ -29,13 +29,12 @@ class SerialNo(StockController):
|
||||
self.via_stock_ledger = False
|
||||
|
||||
def validate(self):
|
||||
if self.get("__islocal") and self.warehouse:
|
||||
if self.get("__islocal") and self.warehouse and not self.via_stock_ledger:
|
||||
frappe.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError)
|
||||
|
||||
self.set_maintenance_status()
|
||||
self.validate_warehouse()
|
||||
self.validate_item()
|
||||
self.on_stock_ledger_entry()
|
||||
|
||||
def set_maintenance_status(self):
|
||||
if not self.warranty_expiry_date and not self.amc_expiry_date:
|
||||
@ -68,7 +67,7 @@ class SerialNo(StockController):
|
||||
"""
|
||||
Validate whether serial no is required for this item
|
||||
"""
|
||||
item = frappe.get_doc("Item", self.item_code)
|
||||
item = frappe.get_cached_doc("Item", self.item_code)
|
||||
if item.has_serial_no!=1:
|
||||
frappe.throw(_("Item {0} is not setup for Serial Nos. Check Item master").format(self.item_code))
|
||||
|
||||
@ -117,9 +116,9 @@ class SerialNo(StockController):
|
||||
"warranty_expiry_date"):
|
||||
self.set(fieldname, None)
|
||||
|
||||
def get_last_sle(self):
|
||||
def get_last_sle(self, serial_no=None):
|
||||
entries = {}
|
||||
sle_dict = self.get_stock_ledger_entries()
|
||||
sle_dict = self.get_stock_ledger_entries(serial_no)
|
||||
if sle_dict:
|
||||
if sle_dict.get("incoming", []):
|
||||
entries["purchase_sle"] = sle_dict["incoming"][0]
|
||||
@ -132,13 +131,28 @@ class SerialNo(StockController):
|
||||
|
||||
return entries
|
||||
|
||||
def get_stock_ledger_entries(self):
|
||||
def get_stock_ledger_entries(self, serial_no=None):
|
||||
sle_dict = {}
|
||||
for sle in frappe.db.sql("""select * from `tabStock Ledger Entry`
|
||||
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'
|
||||
order by posting_date desc, posting_time desc, creation desc""",
|
||||
("%%%s%%" % self.name, self.item_code), as_dict=1):
|
||||
if self.name.upper() in get_serial_nos(sle.serial_no):
|
||||
if not serial_no:
|
||||
serial_no = self.name
|
||||
|
||||
for sle in frappe.db.sql("""
|
||||
SELECT voucher_type, voucher_no,
|
||||
posting_date, posting_time, incoming_rate, actual_qty, serial_no
|
||||
FROM
|
||||
`tabStock Ledger Entry`
|
||||
WHERE
|
||||
item_code=%s AND company = %s AND ifnull(is_cancelled, 'No')='No'
|
||||
AND (serial_no = %s
|
||||
OR serial_no like %s
|
||||
OR serial_no like %s
|
||||
OR serial_no like %s
|
||||
)
|
||||
ORDER BY
|
||||
posting_date desc, posting_time desc, creation desc""",
|
||||
(self.item_code, self.company,
|
||||
serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'), as_dict=1):
|
||||
if serial_no.upper() in get_serial_nos(sle.serial_no):
|
||||
if cint(sle.actual_qty) > 0:
|
||||
sle_dict.setdefault("incoming", []).append(sle)
|
||||
else:
|
||||
@ -178,12 +192,11 @@ class SerialNo(StockController):
|
||||
where name=%s""" % (dt[0], '%s', '%s'),
|
||||
('\n'.join(list(serial_nos)), item[0]))
|
||||
|
||||
def on_stock_ledger_entry(self):
|
||||
if self.via_stock_ledger and not self.get("__islocal"):
|
||||
last_sle = self.get_last_sle()
|
||||
self.set_purchase_details(last_sle.get("purchase_sle"))
|
||||
self.set_sales_details(last_sle.get("delivery_sle"))
|
||||
self.set_maintenance_status()
|
||||
def update_serial_no_reference(self, serial_no=None):
|
||||
last_sle = self.get_last_sle(serial_no)
|
||||
self.set_purchase_details(last_sle.get("purchase_sle"))
|
||||
self.set_sales_details(last_sle.get("delivery_sle"))
|
||||
self.set_maintenance_status()
|
||||
|
||||
def process_serial_no(sle):
|
||||
item_det = get_item_details(sle.item_code)
|
||||
@ -368,6 +381,7 @@ def auto_make_serial_nos(args):
|
||||
if sr.sales_order and voucher_type == "Stock Entry" \
|
||||
and not args.get('actual_qty', 0) > 0:
|
||||
sr.sales_order = None
|
||||
sr.update_serial_no_reference()
|
||||
sr.save(ignore_permissions=True)
|
||||
elif args.get('actual_qty', 0) > 0:
|
||||
created_numbers.append(make_serial_no(serial_no, args))
|
||||
@ -407,27 +421,16 @@ def get_serial_nos(serial_no):
|
||||
|
||||
def make_serial_no(serial_no, args):
|
||||
sr = frappe.new_doc("Serial No")
|
||||
sr.warehouse = None
|
||||
sr.dont_update_if_missing.append("warehouse")
|
||||
sr.flags.ignore_permissions = True
|
||||
sr.serial_no = serial_no
|
||||
sr.item_code = args.get('item_code')
|
||||
sr.company = args.get('company')
|
||||
sr.batch_no = args.get('batch_no')
|
||||
sr.via_stock_ledger = args.get('via_stock_ledger') or True
|
||||
sr.asset = args.get('asset')
|
||||
sr.location = args.get('location')
|
||||
sr.warehouse = args.get('warehouse')
|
||||
|
||||
|
||||
if args.get('purchase_document_type'):
|
||||
sr.purchase_document_type = args.get('purchase_document_type')
|
||||
sr.purchase_document_no = args.get('purchase_document_no')
|
||||
sr.supplier = args.get('supplier')
|
||||
|
||||
sr.insert()
|
||||
if args.get('warehouse'):
|
||||
sr.warehouse = args.get('warehouse')
|
||||
sr.save()
|
||||
sr.validate_item()
|
||||
sr.update_serial_no_reference(serial_no)
|
||||
sr.db_insert()
|
||||
|
||||
return sr.name
|
||||
|
||||
@ -494,10 +497,11 @@ def get_delivery_note_serial_no(item_code, qty, delivery_note):
|
||||
return serial_nos
|
||||
|
||||
@frappe.whitelist()
|
||||
def auto_fetch_serial_number(qty, item_code, warehouse):
|
||||
def auto_fetch_serial_number(qty, item_code, warehouse, batch_no=None):
|
||||
serial_numbers = frappe.get_list("Serial No", filters={
|
||||
"item_code": item_code,
|
||||
"warehouse": warehouse,
|
||||
"batch_no": batch_no,
|
||||
"delivery_document_no": "",
|
||||
"sales_invoice": ""
|
||||
}, limit=qty, order_by="creation")
|
||||
|
@ -1054,7 +1054,7 @@ class StockEntry(StockController):
|
||||
req_qty_each = flt(req_qty / manufacturing_qty)
|
||||
consumed_qty = flt(req_items[0].consumed_qty)
|
||||
|
||||
if trans_qty and manufacturing_qty >= (produced_qty + flt(self.fg_completed_qty)):
|
||||
if trans_qty and manufacturing_qty > (produced_qty + flt(self.fg_completed_qty)):
|
||||
if qty >= req_qty:
|
||||
qty = (req_qty/trans_qty) * flt(self.fg_completed_qty)
|
||||
else:
|
||||
|
@ -180,7 +180,7 @@ def get_child_warehouses(warehouse):
|
||||
lft, rgt = frappe.get_cached_value("Warehouse", warehouse, [lft, rgt])
|
||||
|
||||
return frappe.db.sql_list("""select name from `tabWarehouse`
|
||||
where lft >= %s and rgt =< %s""", (lft, rgt))
|
||||
where lft >= %s and rgt <= %s""", (lft, rgt))
|
||||
|
||||
def get_warehouses_based_on_account(account, company=None):
|
||||
warehouses = []
|
||||
@ -199,4 +199,4 @@ def get_warehouses_based_on_account(account, company=None):
|
||||
frappe.throw(_("Warehouse not found against the account {0}")
|
||||
.format(account))
|
||||
|
||||
return warehouses
|
||||
return warehouses
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cypress": "^3.4.1",
|
||||
"devdependencies": {
|
||||
"snyk": "^1.290.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
Loading…
Reference in New Issue
Block a user