Compare commits
29 Commits
v11.0.3-be
...
v10.1.78
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c8e4fd130 | ||
|
|
1e61dd024b | ||
|
|
7bea25a23a | ||
|
|
61c781325d | ||
|
|
1ed819bb10 | ||
|
|
f0571ddf4b | ||
|
|
d98315c41c | ||
|
|
529cc1ca51 | ||
|
|
d36bc5a9fd | ||
|
|
876d868fa1 | ||
|
|
9080221d46 | ||
|
|
acd7f73d57 | ||
|
|
910a744263 | ||
|
|
4ed7cfc515 | ||
|
|
7facc34851 | ||
|
|
0d208851a4 | ||
|
|
f99e013ebc | ||
|
|
6b466fe230 | ||
|
|
07cf4e8f5b | ||
|
|
2825b929c1 | ||
|
|
d40743a570 | ||
|
|
75ab042632 | ||
|
|
547229fef1 | ||
|
|
47c9826b6f | ||
|
|
53c040f838 | ||
|
|
a09a6e4020 | ||
|
|
cacbdec565 | ||
|
|
fcbe410c2f | ||
|
|
52a692ee08 |
11
.travis.yml
11
.travis.yml
@@ -30,17 +30,16 @@ before_script:
|
||||
- cd ~/frappe-bench
|
||||
- bench get-app erpnext $TRAVIS_BUILD_DIR
|
||||
- bench use test_site
|
||||
- bench reinstall --yes
|
||||
- bench build
|
||||
- bench scheduler disable
|
||||
- sed -i 's/9000/9001/g' sites/common_site_config.json
|
||||
- bench start &
|
||||
- sleep 10
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
script:
|
||||
- bench reinstall --yes
|
||||
- bench scheduler disable
|
||||
- sed -i 's/9000/9001/g' sites/common_site_config.json
|
||||
- bench start &
|
||||
- sleep 10
|
||||
- set -e
|
||||
- bench run-tests
|
||||
env: Server Side Test
|
||||
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '10.1.76'
|
||||
__version__ = '10.1.78'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
||||
@@ -18,15 +18,14 @@ class GLEntry(Document):
|
||||
self.flags.ignore_submit_comment = True
|
||||
self.check_mandatory()
|
||||
self.validate_and_set_fiscal_year()
|
||||
self.pl_must_have_cost_center()
|
||||
self.validate_cost_center()
|
||||
|
||||
if not self.flags.from_repost:
|
||||
self.pl_must_have_cost_center()
|
||||
self.check_pl_account()
|
||||
self.validate_cost_center()
|
||||
self.validate_party()
|
||||
self.validate_currency()
|
||||
|
||||
|
||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
||||
if not from_repost:
|
||||
self.validate_account_details(adv_adj)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
execute:import unidecode # new requirement
|
||||
erpnext.patches.v8_0.move_perpetual_inventory_setting
|
||||
erpnext.patches.v8_9.set_print_zero_amount_taxes
|
||||
erpnext.patches.v10_0.rename_schools_to_education
|
||||
erpnext.patches.v4_0.validate_v3_patch
|
||||
erpnext.patches.v4_0.fix_employee_user_id
|
||||
@@ -442,7 +443,6 @@ erpnext.patches.v8_9.add_setup_progress_actions #08-09-2017 #26-09-2017 #22-11-2
|
||||
erpnext.patches.v8_9.rename_company_sales_target_field
|
||||
erpnext.patches.v8_8.set_bom_rate_as_per_uom
|
||||
erpnext.patches.v8_8.add_new_fields_in_accounts_settings
|
||||
erpnext.patches.v8_9.set_print_zero_amount_taxes
|
||||
erpnext.patches.v8_9.set_default_customer_group
|
||||
erpnext.patches.v8_9.remove_employee_from_salary_structure_parent
|
||||
erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts
|
||||
|
||||
@@ -8,22 +8,49 @@ def validate_gstin_for_india(doc, method):
|
||||
if not hasattr(doc, 'gstin'):
|
||||
return
|
||||
|
||||
if doc.gstin:
|
||||
doc.gstin = doc.gstin.upper()
|
||||
if doc.gstin not in ["NA", "na"]:
|
||||
p = re.compile("[0-9]{2}[a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9a-zA-Z]{1}")
|
||||
if not p.match(doc.gstin):
|
||||
frappe.throw(_("Invalid GSTIN or Enter NA for Unregistered"))
|
||||
doc.gstin = doc.gstin.upper().strip()
|
||||
if not doc.gstin or doc.gstin == 'NA':
|
||||
return
|
||||
|
||||
if len(doc.gstin) != 15:
|
||||
frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters."))
|
||||
|
||||
p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
|
||||
if not p.match(doc.gstin):
|
||||
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
|
||||
|
||||
validate_gstin_check_digit(doc.gstin)
|
||||
|
||||
if not doc.gst_state:
|
||||
if doc.state in states:
|
||||
doc.gst_state = doc.state
|
||||
if not doc.state:
|
||||
return
|
||||
state = doc.state.lower()
|
||||
states_lowercase = {s.lower():s for s in states}
|
||||
if state in states_lowercase:
|
||||
doc.gst_state = states_lowercase[state]
|
||||
else:
|
||||
return
|
||||
|
||||
if doc.gst_state:
|
||||
doc.gst_state_number = state_numbers[doc.gst_state]
|
||||
if doc.gstin and doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
|
||||
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
|
||||
.format(doc.gst_state_number))
|
||||
doc.gst_state_number = state_numbers[doc.gst_state]
|
||||
if doc.gst_state_number != doc.gstin[:2]:
|
||||
frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
|
||||
.format(doc.gst_state_number))
|
||||
|
||||
def validate_gstin_check_digit(gstin):
|
||||
''' Function to validate the check digit of the GSTIN.'''
|
||||
factor = 1
|
||||
total = 0
|
||||
code_point_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
mod = len(code_point_chars)
|
||||
input_chars = gstin[:-1]
|
||||
for char in input_chars:
|
||||
digit = factor * code_point_chars.find(char)
|
||||
digit = (digit // mod) + (digit % mod)
|
||||
total += digit
|
||||
factor = 2 if factor == 1 else 1
|
||||
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
|
||||
frappe.throw(_("Invalid GSTIN! The check digit validation has failed. " +
|
||||
"Please ensure you've typed the GSTIN correctly."))
|
||||
|
||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||
|
||||
@@ -173,6 +173,11 @@ class Customer(TransactionBase):
|
||||
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
|
||||
|
||||
def on_trash(self):
|
||||
if self.customer_primary_contact:
|
||||
frappe.db.sql("""update `tabCustomer`
|
||||
set customer_primary_contact=null, mobile_no=null, email_id=null
|
||||
where name=%s""", self.name)
|
||||
|
||||
delete_contact_and_address('Customer', self.name)
|
||||
if self.lead_name:
|
||||
frappe.db.sql("update `tabLead` set status='Interested' where name=%s", self.lead_name)
|
||||
|
||||
@@ -96,6 +96,15 @@ class TestCustomer(unittest.TestCase):
|
||||
|
||||
so.save()
|
||||
|
||||
def test_delete_customer_contact(self):
|
||||
customer = frappe.get_doc(
|
||||
get_customer_dict('_Test Customer for delete')).insert(ignore_permissions=True)
|
||||
|
||||
customer.mobile_no = "8989889890"
|
||||
customer.save()
|
||||
self.assertTrue(customer.customer_primary_contact)
|
||||
frappe.delete_doc('Customer', customer.name)
|
||||
|
||||
def test_disabled_customer(self):
|
||||
make_test_records("Item")
|
||||
|
||||
|
||||
@@ -31,6 +31,26 @@ class TestQuotation(unittest.TestCase):
|
||||
|
||||
self.assertFalse(sales_order.get('payment_schedule'))
|
||||
|
||||
def test_make_sales_order_with_different_currency(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
quotation = frappe.copy_doc(test_records[0])
|
||||
quotation.transaction_date = nowdate()
|
||||
quotation.valid_till = add_months(quotation.transaction_date, 1)
|
||||
quotation.insert()
|
||||
quotation.submit()
|
||||
|
||||
sales_order = make_sales_order(quotation.name)
|
||||
sales_order.currency = "USD"
|
||||
sales_order.conversion_rate = 20.0
|
||||
sales_order.delivery_date = "2019-01-01"
|
||||
sales_order.naming_series = "_T-Quotation-"
|
||||
sales_order.transaction_date = nowdate()
|
||||
sales_order.insert()
|
||||
|
||||
self.assertEquals(sales_order.currency, "USD")
|
||||
self.assertNotEqual(sales_order.currency, quotation.currency)
|
||||
|
||||
def test_make_sales_order(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ class SalesOrder(SellingController):
|
||||
super(SalesOrder, self).validate_with_previous_doc({
|
||||
"Quotation": {
|
||||
"ref_dn_field": "prevdoc_docname",
|
||||
"compare_fields": [["company", "="], ["currency", "="]]
|
||||
"compare_fields": [["company", "="]]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ def place_order():
|
||||
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
|
||||
for item in sales_order.get("items"):
|
||||
item.reserved_warehouse, is_stock_item = frappe.db.get_value("Item",
|
||||
item.item_code, ["website_warehouse", "is_stock_item"]) or None, None
|
||||
item.item_code, ["website_warehouse", "is_stock_item"])
|
||||
|
||||
if is_stock_item:
|
||||
item_stock = get_qty_in_stock(item.item_code, "website_warehouse")
|
||||
|
||||
@@ -5,6 +5,7 @@ $.extend(cur_frm.cscript, {
|
||||
onload: function() {
|
||||
if(cur_frm.doc.__onload && cur_frm.doc.__onload.quotation_series) {
|
||||
cur_frm.fields_dict.quotation_series.df.options = cur_frm.doc.__onload.quotation_series;
|
||||
cur_frm.refresh_field("quotation_series");
|
||||
}
|
||||
},
|
||||
refresh: function(){
|
||||
|
||||
@@ -325,7 +325,8 @@ def make_purchase_receipt(**args):
|
||||
"conversion_factor": args.conversion_factor or 1.0,
|
||||
"serial_no": args.serial_no,
|
||||
"stock_uom": args.stock_uom or "_Test UOM",
|
||||
"uom": args.uom or "_Test UOM"
|
||||
"uom": args.uom or "_Test UOM",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
|
||||
if not args.do_not_save:
|
||||
|
||||
@@ -270,24 +270,27 @@ class StockReconciliation(StockController):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_items(warehouse, posting_date, posting_time):
|
||||
items = frappe.get_list("Bin", fields=["item_code"], filters={"warehouse": warehouse}, as_list=1)
|
||||
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||
items = frappe.db.sql("""select item_code, warehouse from tabBin
|
||||
where exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=`tabBin`.warehouse)
|
||||
""", (lft, rgt))
|
||||
|
||||
items += frappe.get_list("Item", fields=["name"], filters= {"is_stock_item": 1, "has_serial_no": 0,
|
||||
"has_batch_no": 0, "has_variants": 0, "disabled": 0, "default_warehouse": warehouse},
|
||||
as_list=1)
|
||||
items += frappe.db.sql("""select name, default_warehouse from tabItem
|
||||
where exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=`tabItem`.default_warehouse)
|
||||
and is_stock_item = 1 and has_serial_no = 0 and has_batch_no = 0 and has_variants = 0 and disabled = 0
|
||||
""", (lft, rgt))
|
||||
|
||||
res = []
|
||||
for item in set(items):
|
||||
stock_bal = get_stock_balance(item[0], warehouse, posting_date, posting_time,
|
||||
for item, wh in set(items):
|
||||
stock_bal = get_stock_balance(item, wh, posting_date, posting_time,
|
||||
with_valuation_rate=True)
|
||||
|
||||
if frappe.db.get_value("Item",item[0],"disabled") == 0:
|
||||
|
||||
if frappe.db.get_value("Item", item, "disabled") == 0:
|
||||
res.append({
|
||||
"item_code": item[0],
|
||||
"warehouse": warehouse,
|
||||
"item_code": item,
|
||||
"warehouse": wh,
|
||||
"qty": stock_bal[0],
|
||||
"item_name": frappe.db.get_value('Item', item[0], 'item_name'),
|
||||
"item_name": frappe.db.get_value('Item', item, 'item_name'),
|
||||
"valuation_rate": stock_bal[1],
|
||||
"current_qty": stock_bal[0],
|
||||
"current_valuation_rate": stock_bal[1]
|
||||
|
||||
@@ -10,7 +10,9 @@ from frappe.utils import flt, nowdate, nowtime
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
|
||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError
|
||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
class TestStockReconciliation(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -79,6 +81,17 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
def test_get_items(self):
|
||||
create_warehouse("_Test Warehouse Group 1", {"is_group": 1})
|
||||
create_warehouse("_Test Warehouse Ledger 1", {"is_group": 0, "parent_warehouse": "_Test Warehouse Group 1 - _TC"})
|
||||
make_item("_Test Stock Reco Item", {"default_warehouse": "_Test Warehouse Ledger 1 - _TC",
|
||||
"is_stock_item": 1, "opening_stock": 100, "valuation_rate": 100})
|
||||
|
||||
items = get_items("_Test Warehouse Group 1 - _TC", nowdate(), nowtime())
|
||||
|
||||
self.assertEqual(["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100],
|
||||
[items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]])
|
||||
|
||||
def insert_existing_sle(self):
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class TestWarehouse(unittest.TestCase):
|
||||
self.assertTrue(frappe.db.get_value("Warehouse",
|
||||
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
|
||||
|
||||
def create_warehouse(warehouse_name):
|
||||
def create_warehouse(warehouse_name, properties=None):
|
||||
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
|
||||
w = frappe.new_doc("Warehouse")
|
||||
w.warehouse_name = warehouse_name
|
||||
@@ -98,11 +98,13 @@ def create_warehouse(warehouse_name):
|
||||
w.company = "_Test Company"
|
||||
make_account_for_warehouse(warehouse_name, w)
|
||||
w.account = warehouse_name + " - _TC"
|
||||
if properties:
|
||||
w.update(properties)
|
||||
w.save()
|
||||
|
||||
def make_account_for_warehouse(warehouse_name, warehouse_obj):
|
||||
if not frappe.db.exists("Account", warehouse_name + " - _TC"):
|
||||
parent_account = frappe.db.get_value('Account',
|
||||
parent_account = frappe.db.get_value('Account',
|
||||
{'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name')
|
||||
account = create_account(account_name=warehouse_name, \
|
||||
account_type="Stock", parent_account= parent_account, company=warehouse_obj.company)
|
||||
Reference in New Issue
Block a user