Merge branch 'develop' of https://github.com/frappe/erpnext into develop

This commit is contained in:
0Pranav 2019-10-25 11:45:03 +05:30
commit 8c1b88f156
29 changed files with 270 additions and 139 deletions

47
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,47 @@
---
name: Bug report
about: Report a bug encountered while using ERPNext
labels: bug
---
<!--
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
- For questions and general support, checkout the manual https://erpnext.com/docs/user/manual/en or use https://discuss.erpnext.com
- For documentation issues, refer to https://github.com/frappe/erpnext_com
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
maintainers to reproduce, the faster it'll be fixed.
4. If you think you know what the reason for the bug is, share it with us. Maybe put in a PR 😉
-->
## Description of the issue
## Context information (for bug reports)
**Output of `bench version`**
```
(paste here)
```
## Steps to reproduce the issue
1.
2.
3.
### Observed result
### Expected result
### Stacktrace / full error message
```
(paste here)
```
## Additional information
OS version / distribution, `ERPNext` install method, etc.

View File

@ -0,0 +1,28 @@
---
name: Feature request
about: Suggest an idea to improve ERPNext
labels: feature-request
---
<!--
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
- For questions and general support, checkout the manual https://erpnext.com/docs/user/manual/en or use https://discuss.erpnext.com
- For documentation issues, refer to https://github.com/frappe/erpnext_com
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
the original discussion.
3. When making a feature request, make sure to be as verbose as possible. The better you convey your message, the greater the drive to make it happen.
-->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,17 @@
---
name: Question about using ERPNext
about: This is not the appropriate channel
labels: invalid
---
Please post on our forums:
for questions about using `ERPNext`: https://discuss.erpnext.com
for questions about using the `Frappe Framework`: https://discuss.frappe.io
for questions about using `bench`, probably the best place to start is the [bench repo](https://github.com/frappe/bench)
For documentation issues, use the [ERPNext Documentation](https://erpnext.com/docs/) or [Frappe Framework Documentation](https://frappe.io/docs/user/en) or the [developer cheetsheet](https://github.com/frappe/frappe/wiki/Developer-Cheatsheet)
> **Posts that are not bug reports or feature requests will not be addressed on this issue tracker.**

View File

@ -1,2 +1,33 @@
Please read the pull request checklist to make sure your changes are merged: https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist <!--
Some key notes before you open a PR:
1. Select which branch should this PR be merged in?
2. PR name follows [convention](http://karma-runner.github.io/4.0/dev/git-commit-msg.html)
3. All tests pass locally, UI and Unit tests
4. All business logic and validations must be on the server-side
5. Update necessary Documentation
6. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes
Also, if you're new here
- Documentation Guidelines => https://github.com/frappe/erpnext/wiki/Updating-Documentation
- Contribution Guide => https://github.com/frappe/erpnext/blob/develop/.github/CONTRIBUTING.md
- Pull Request Checklist => https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist
-->
> Please provide enough information so that others can review your pull request:
<!-- You can skip this if you're fixing a typo or updating existing documentation -->
> Explain the **details** for making this change. What existing problem does the pull request solve?
<!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
> Screenshots/GIFs
<!-- Add images/recordings to better visualize the change: expected/current behviour -->

7
SECURITY.md Normal file
View File

@ -0,0 +1,7 @@
# Security Policy
The ERPNext team and community take security issues seriously. To report a security issue, fill out the form at [https://erpnext.com/security/report](https://erpnext.com/security/report).
You can help us make ERPNext and all it's users more secure by following the [Reporting guidelines](https://erpnext.com/security).
We appreciate your efforts to responsibly disclose your findings. We'll endeavor to respond quickly, and will keep you updated throughout the process.

View File

@ -1,13 +1,13 @@
{ {
"add_total_row": 0, "add_total_row": 0,
"creation": "2019-09-23 16:35:02.836134", "creation": "2019-09-23 16:35:02.836134",
"disable_prepared_report": 0, "disable_prepared_report": 1,
"disabled": 0, "disabled": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Report", "doctype": "Report",
"idx": 0, "idx": 0,
"is_standard": "Yes", "is_standard": "Yes",
"modified": "2019-09-23 16:35:02.836134", "modified": "2019-10-22 13:00:31.539726",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Fixed Asset Register", "name": "Fixed Asset Register",

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.utils import cstr
def execute(filters=None): def execute(filters=None):
filters = frappe._dict(filters or {}) filters = frappe._dict(filters or {})
@ -149,7 +150,7 @@ def get_finance_book_value_map(finance_book=''):
FROM `tabAsset Finance Book` FROM `tabAsset Finance Book`
WHERE WHERE
parentfield='finance_books' parentfield='finance_books'
AND finance_book=%s''', (finance_book))) AND ifnull(finance_book, '')=%s''', cstr(finance_book)))
def get_purchase_receipt_supplier_map(): def get_purchase_receipt_supplier_map():
return frappe._dict(frappe.db.sql(''' Select return frappe._dict(frappe.db.sql(''' Select

View File

@ -18,7 +18,7 @@ def get_data():
"onboard_present": 1 "onboard_present": 1
}, },
{ {
"module_name": "Accounting", "module_name": "Accounts",
"category": "Modules", "category": "Modules",
"label": _("Accounting"), "label": _("Accounting"),
"color": "#3498db", "color": "#3498db",

View File

@ -127,7 +127,11 @@ def get_data():
"name": "Shipping Rule", "name": "Shipping Rule",
"description": _("Rules for adding shipping costs."), "description": _("Rules for adding shipping costs."),
}, },
{
"type": "doctype",
"name": "Coupon Code",
"description": _("Define coupon codes."),
}
] ]
}, },
{ {

View File

@ -280,8 +280,13 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
"page_len": page_len "page_len": page_len
} }
having_clause = "having sum(sle.actual_qty) > 0"
if filters.get("is_return"):
having_clause = ""
if args.get('warehouse'): if args.get('warehouse'):
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom, concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date) batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom,
concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
from `tabStock Ledger Entry` sle from `tabStock Ledger Entry` sle
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
where where
@ -291,11 +296,15 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
and (sle.batch_no like %(txt)s and (sle.batch_no like %(txt)s
or batch.manufacturing_date like %(txt)s) or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2 and batch.docstatus < 2
{0} {cond}
{match_conditions} {match_conditions}
group by batch_no having sum(sle.actual_qty) > 0 group by batch_no {having_clause}
order by batch.expiry_date, sle.batch_no desc order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args) limit %(start)s, %(page_len)s""".format(
cond=cond,
match_conditions=get_match_cond(doctype),
having_clause = having_clause
), args)
return batch_nos return batch_nos
else: else:

View File

@ -10,13 +10,14 @@ from erpnext.demo.domains import data
from frappe import _ from frappe import _
def setup(domain): def setup(domain):
frappe.flags.in_demo = 1
complete_setup(domain) complete_setup(domain)
setup_demo_page() setup_demo_page()
setup_fiscal_year() setup_fiscal_year()
setup_holiday_list() setup_holiday_list()
setup_user() setup_user()
setup_employee() setup_employee()
setup_user_roles() setup_user_roles(domain)
setup_role_permissions() setup_role_permissions()
setup_custom_field_for_domain() setup_custom_field_for_domain()
@ -183,14 +184,20 @@ def setup_salary_structure(employees, salary_slip_based_on_timesheet=0):
return ss return ss
def setup_user_roles(): def setup_user_roles(domain):
user = frappe.get_doc('User', 'demo@erpnext.com') user = frappe.get_doc('User', 'demo@erpnext.com')
user.add_roles('HR User', 'HR Manager', 'Accounts User', 'Accounts Manager', user.add_roles('HR User', 'HR Manager', 'Accounts User', 'Accounts Manager',
'Stock User', 'Stock Manager', 'Sales User', 'Sales Manager', 'Purchase User', 'Stock User', 'Stock Manager', 'Sales User', 'Sales Manager', 'Purchase User',
'Purchase Manager', 'Projects User', 'Manufacturing User', 'Manufacturing Manager', 'Purchase Manager', 'Projects User', 'Manufacturing User', 'Manufacturing Manager',
'Support Team', 'Academics User', 'Physician', 'Healthcare Administrator', 'Laboratory User', 'Support Team')
if domain == "Healthcare":
user.add_roles('Physician', 'Healthcare Administrator', 'Laboratory User',
'Nursing User', 'Patient') 'Nursing User', 'Patient')
if domain == "Education":
user.add_roles('Academics User')
if not frappe.db.get_global('demo_hr_user'): if not frappe.db.get_global('demo_hr_user'):
user = frappe.get_doc('User', 'CaitlinSnow@example.com') user = frappe.get_doc('User', 'CaitlinSnow@example.com')
user.add_roles('HR User', 'HR Manager', 'Accounts User') user.add_roles('HR User', 'HR Manager', 'Accounts User')
@ -219,7 +226,7 @@ def setup_user_roles():
if not frappe.db.get_global('demo_manufacturing_user'): if not frappe.db.get_global('demo_manufacturing_user'):
user = frappe.get_doc('User', 'NeptuniaAquaria@example.com') user = frappe.get_doc('User', 'NeptuniaAquaria@example.com')
user.add_roles('Manufacturing User', 'Stock User', 'Purchase User', 'Accounts User') user.add_roles('Manufacturing User', 'Stock Manager', 'Stock User', 'Purchase User', 'Accounts User')
update_employee_department(user.name, 'Production') update_employee_department(user.name, 'Production')
frappe.db.set_global('demo_manufacturing_user', user.name) frappe.db.set_global('demo_manufacturing_user', user.name)
@ -241,6 +248,7 @@ def setup_user_roles():
update_employee_department(user.name, 'Management') update_employee_department(user.name, 'Management')
frappe.db.set_global('demo_projects_user', user.name) frappe.db.set_global('demo_projects_user', user.name)
if domain == "Education":
if not frappe.db.get_global('demo_education_user'): if not frappe.db.get_global('demo_education_user'):
user = frappe.get_doc('User', 'ArthurCurry@example.com') user = frappe.get_doc('User', 'ArthurCurry@example.com')
user.add_roles('Academics User') user.add_roles('Academics User')

View File

@ -73,14 +73,16 @@ def work():
make_pos_invoice() make_pos_invoice()
def make_payment_entries(ref_doctype, report): def make_payment_entries(ref_doctype, report):
outstanding_invoices = list(set([r[3] for r in query_report.run(report, {
"report_date": frappe.flags.current_date, outstanding_invoices = frappe.get_all(ref_doctype, fields=["name"],
"company": erpnext.get_default_company() filters={
})["result"] if r[2]==ref_doctype])) "company": erpnext.get_default_company(),
"outstanding_amount": (">", 0.0)
})
# make Payment Entry # make Payment Entry
for inv in outstanding_invoices[:random.randint(1, 2)]: for inv in outstanding_invoices[:random.randint(1, 2)]:
pe = get_payment_entry(ref_doctype, inv) pe = get_payment_entry(ref_doctype, inv.name)
pe.posting_date = frappe.flags.current_date pe.posting_date = frappe.flags.current_date
pe.reference_no = random_string(6) pe.reference_no = random_string(6)
pe.reference_date = frappe.flags.current_date pe.reference_date = frappe.flags.current_date
@ -91,7 +93,7 @@ def make_payment_entries(ref_doctype, report):
# make payment via JV # make payment via JV
for inv in outstanding_invoices[:1]: for inv in outstanding_invoices[:1]:
jv = frappe.get_doc(get_payment_entry_against_invoice(ref_doctype, inv)) jv = frappe.get_doc(get_payment_entry_against_invoice(ref_doctype, inv.name))
jv.posting_date = frappe.flags.current_date jv.posting_date = frappe.flags.current_date
jv.cheque_no = random_string(6) jv.cheque_no = random_string(6)
jv.cheque_date = frappe.flags.current_date jv.cheque_date = frappe.flags.current_date

View File

@ -39,61 +39,4 @@ def make_project(current_date):
"doctype": "Project", "doctype": "Project",
"project_name": "New Product Development " + current_date.strftime("%Y-%m-%d"), "project_name": "New Product Development " + current_date.strftime("%Y-%m-%d"),
}) })
project.set("tasks", [
{
"title": "Review Requirements",
"start_date": frappe.utils.add_days(current_date, 10),
"end_date": frappe.utils.add_days(current_date, 11)
},
{
"title": "Design Options",
"start_date": frappe.utils.add_days(current_date, 11),
"end_date": frappe.utils.add_days(current_date, 20)
},
{
"title": "Make Prototypes",
"start_date": frappe.utils.add_days(current_date, 20),
"end_date": frappe.utils.add_days(current_date, 30)
},
{
"title": "Customer Feedback on Prototypes",
"start_date": frappe.utils.add_days(current_date, 30),
"end_date": frappe.utils.add_days(current_date, 40)
},
{
"title": "Freeze Feature Set",
"start_date": frappe.utils.add_days(current_date, 40),
"end_date": frappe.utils.add_days(current_date, 45)
},
{
"title": "Testing",
"start_date": frappe.utils.add_days(current_date, 45),
"end_date": frappe.utils.add_days(current_date, 60)
},
{
"title": "Product Engineering",
"start_date": frappe.utils.add_days(current_date, 45),
"end_date": frappe.utils.add_days(current_date, 55)
},
{
"title": "Supplier Contracts",
"start_date": frappe.utils.add_days(current_date, 55),
"end_date": frappe.utils.add_days(current_date, 70)
},
{
"title": "Design and Build Fixtures",
"start_date": frappe.utils.add_days(current_date, 45),
"end_date": frappe.utils.add_days(current_date, 65)
},
{
"title": "Test Run",
"start_date": frappe.utils.add_days(current_date, 70),
"end_date": frappe.utils.add_days(current_date, 80)
},
{
"title": "Launch",
"start_date": frappe.utils.add_days(current_date, 80),
"end_date": frappe.utils.add_days(current_date, 90)
},
])
project.insert() project.insert()

View File

@ -66,7 +66,7 @@ def make_opportunity(domain):
b = frappe.get_doc({ b = frappe.get_doc({
"doctype": "Opportunity", "doctype": "Opportunity",
"opportunity_from": "Customer", "opportunity_from": "Customer",
"customer": get_random("Customer"), "party_name": frappe.get_value("Customer", get_random("Customer"), 'name'),
"opportunity_type": "Sales", "opportunity_type": "Sales",
"with_items": 1, "with_items": 1,
"transaction_date": frappe.flags.current_date, "transaction_date": frappe.flags.current_date,

View File

@ -29,7 +29,8 @@ def sync_sales_order(order, request_id=None):
validate_item(order, shopify_settings) validate_item(order, shopify_settings)
create_order(order, shopify_settings) create_order(order, shopify_settings)
except Exception as e: except Exception as e:
make_shopify_log(status="Error", message=e.message, exception=False) make_shopify_log(status="Error", exception=e)
else: else:
make_shopify_log(status="Success") make_shopify_log(status="Success")
@ -43,8 +44,8 @@ def prepare_sales_invoice(order, request_id=None):
if sales_order: if sales_order:
create_sales_invoice(order, shopify_settings, sales_order) create_sales_invoice(order, shopify_settings, sales_order)
make_shopify_log(status="Success") make_shopify_log(status="Success")
except Exception: except Exception as e:
make_shopify_log(status="Error", exception=True) make_shopify_log(status="Error", exception=e, rollback=True)
def prepare_delivery_note(order, request_id=None): def prepare_delivery_note(order, request_id=None):
frappe.set_user('Administrator') frappe.set_user('Administrator')
@ -56,8 +57,8 @@ def prepare_delivery_note(order, request_id=None):
if sales_order: if sales_order:
create_delivery_note(order, shopify_settings, sales_order) create_delivery_note(order, shopify_settings, sales_order)
make_shopify_log(status="Success") make_shopify_log(status="Success")
except Exception: except Exception as e:
make_shopify_log(status="Error", exception=True) make_shopify_log(status="Error", exception=e, rollback=True)
def get_sales_order(shopify_order_id): def get_sales_order(shopify_order_id):
sales_order = frappe.db.get_value("Sales Order", filters={"shopify_order_id": shopify_order_id}) sales_order = frappe.db.get_value("Sales Order", filters={"shopify_order_id": shopify_order_id})
@ -97,7 +98,7 @@ def create_sales_order(shopify_order, shopify_settings, company=None):
message = 'Following items are exists in order but relevant record not found in Product master' message = 'Following items are exists in order but relevant record not found in Product master'
message += "\n" + ", ".join(product_not_exists) message += "\n" + ", ".join(product_not_exists)
make_shopify_log(status="Error", message=message, exception=True) make_shopify_log(status="Error", exception=e, rollback=True)
return '' return ''

View File

@ -12,23 +12,38 @@ class ShopifyLog(Document):
pass pass
def make_shopify_log(status="Queued", message=None, exception=False): def make_shopify_log(status="Queued", exception=None, rollback=False):
# if name not provided by log calling method then fetch existing queued state log # if name not provided by log calling method then fetch existing queued state log
make_new = False
if not frappe.flags.request_id: if not frappe.flags.request_id:
return make_new = True
log = frappe.get_doc("Shopify Log", frappe.flags.request_id) if rollback:
if exception:
frappe.db.rollback() frappe.db.rollback()
log = frappe.get_doc({"doctype":"Shopify Log"}).insert(ignore_permissions=True)
log.message = message if message else '' if make_new:
log = frappe.get_doc({"doctype":"Shopify Log"}).insert(ignore_permissions=True)
else:
log = log = frappe.get_doc("Shopify Log", frappe.flags.request_id)
log.message = get_message(exception)
log.traceback = frappe.get_traceback() log.traceback = frappe.get_traceback()
log.status = status log.status = status
log.save(ignore_permissions=True) log.save(ignore_permissions=True)
frappe.db.commit() frappe.db.commit()
def get_message(exception):
message = None
if hasattr(exception, 'message'):
message = exception.message
elif hasattr(exception, '__str__'):
message = e.__str__()
else:
message = "Something went wrong while syncing"
return message
def dump_request_data(data, event="create/order"): def dump_request_data(data, event="create/order"):
event_mapper = { event_mapper = {
"orders/create": get_webhook_address(connector_name='shopify_connection', method="sync_sales_order", exclude_uri=True), "orders/create": get_webhook_address(connector_name='shopify_connection', method="sync_sales_order", exclude_uri=True),

View File

@ -30,13 +30,9 @@ class ShopifySettings(Document):
# url = get_shopify_url('admin/webhooks.json', self) # url = get_shopify_url('admin/webhooks.json', self)
created_webhooks = [d.method for d in self.webhooks] created_webhooks = [d.method for d in self.webhooks]
url = get_shopify_url('admin/api/2019-04/webhooks.json', self) url = get_shopify_url('admin/api/2019-04/webhooks.json', self)
print('url', url)
for method in webhooks: for method in webhooks:
print('method', method)
session = get_request_session() session = get_request_session()
print('session', session)
try: try:
print(get_header(self))
d = session.post(url, data=json.dumps({ d = session.post(url, data=json.dumps({
"webhook": { "webhook": {
"topic": method, "topic": method,
@ -44,7 +40,6 @@ class ShopifySettings(Document):
"format": "json" "format": "json"
} }
}), headers=get_header(self)) }), headers=get_header(self))
print('d', d.json())
d.raise_for_status() d.raise_for_status()
self.update_webhook_table(method, d.json()) self.update_webhook_table(method, d.json())
except Exception as e: except Exception as e:
@ -67,7 +62,6 @@ class ShopifySettings(Document):
self.remove(d) self.remove(d)
def update_webhook_table(self, method, res): def update_webhook_table(self, method, res):
print('update')
self.append("webhooks", { self.append("webhooks", {
"webhook_id": res['webhook']['id'], "webhook_id": res['webhook']['id'],
"method": method "method": method
@ -75,7 +69,6 @@ class ShopifySettings(Document):
def get_shopify_url(path, settings): def get_shopify_url(path, settings):
if settings.app_type == "Private": if settings.app_type == "Private":
print(settings.api_key, settings.get_password('password'), settings.shopify_url, path)
return 'https://{}:{}@{}/{}'.format(settings.api_key, settings.get_password('password'), settings.shopify_url, path) return 'https://{}:{}@{}/{}'.format(settings.api_key, settings.get_password('password'), settings.shopify_url, path)
else: else:
return 'https://{}/{}'.format(settings.shopify_url, path) return 'https://{}/{}'.format(settings.shopify_url, path)

View File

@ -12,6 +12,7 @@ frappe.ui.form.on('Blanket Order', {
}, },
refresh: function(frm) { refresh: function(frm) {
erpnext.hide_company();
if (frm.doc.customer && frm.doc.docstatus === 1) { if (frm.doc.customer && frm.doc.docstatus === 1) {
frm.add_custom_button(__('View Orders'), function() { frm.add_custom_button(__('View Orders'), function() {
frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name}); frappe.set_route('List', 'Sales Order', {blanket_order: frm.doc.name});
@ -51,11 +52,19 @@ frappe.ui.form.on('Blanket Order', {
set_tc_name_filter: function(frm) { set_tc_name_filter: function(frm) {
if (frm.doc.blanket_order_type === 'Selling') { if (frm.doc.blanket_order_type === 'Selling') {
frm.set_df_property("customer","reqd", 1);
frm.set_df_property("supplier","reqd", 0);
frm.set_value("supplier", "");
frm.set_query("tc_name", function() { frm.set_query("tc_name", function() {
return { filters: { selling: 1 } }; return { filters: { selling: 1 } };
}); });
} }
if (frm.doc.blanket_order_type === 'Purchasing') { if (frm.doc.blanket_order_type === 'Purchasing') {
frm.set_df_property("supplier","reqd", 1);
frm.set_df_property("customer","reqd", 0);
frm.set_value("customer", "");
frm.set_query("tc_name", function() { frm.set_query("tc_name", function() {
return { filters: { buying: 1 } }; return { filters: { buying: 1 } };
}); });

View File

@ -88,7 +88,8 @@
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Company", "label": "Company",
"options": "Company" "options": "Company",
"reqd": 1
}, },
{ {
"fieldname": "section_break_12", "fieldname": "section_break_12",
@ -128,7 +129,7 @@
} }
], ],
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-06-19 11:59:09.279607", "modified": "2019-10-16 13:38:32.302316",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Blanket Order", "name": "Blanket Order",

View File

@ -4,13 +4,21 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import flt from frappe import _
from frappe.utils import flt, getdate
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.stock.doctype.item.item import get_item_defaults
class BlanketOrder(Document): class BlanketOrder(Document):
def validate(self):
self.validate_dates()
def validate_dates(self):
if getdate(self.from_date) > getdate(self.to_date):
frappe.throw(_("From date cannot be greater than To date"))
def update_ordered_qty(self): def update_ordered_qty(self):
ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order" ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order"
item_ordered_qty = frappe._dict(frappe.db.sql(""" item_ordered_qty = frappe._dict(frappe.db.sql("""

View File

@ -35,7 +35,8 @@ class BOM(WebsiteGenerator):
# name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1 # name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1
# split by item # split by item
names = [name.split(self.item)[-1][1:] for name in names] names = [name.split(self.item, 1) for name in names]
names = [d[-1][1:] for d in filter(lambda x: len(x) > 1 and x[-1], names)]
# split by (-) if cancelled # split by (-) if cancelled
names = [cint(name.split('-')[-1]) for name in names] names = [cint(name.split('-')[-1]) for name in names]

View File

@ -4,7 +4,7 @@ from frappe.model.utils.rename_field import rename_field
def execute(): def execute():
frappe.reload_doc('desk', 'doctype', 'auto_repeat') frappe.reload_doc('automation', 'doctype', 'auto_repeat')
doctypes_to_rename = { doctypes_to_rename = {
'accounts': ['Journal Entry', 'Payment Entry', 'Purchase Invoice', 'Sales Invoice'], 'accounts': ['Journal Entry', 'Payment Entry', 'Purchase Invoice', 'Sales Invoice'],

View File

@ -1653,6 +1653,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
'item_code': item.item_code, 'item_code': item.item_code,
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(), 'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
} }
if (doc.is_return) {
filters["is_return"] = 1;
}
if (item.warehouse) filters["warehouse"] = item.warehouse; if (item.warehouse) filters["warehouse"] = item.warehouse;
return { return {

View File

@ -1185,6 +1185,7 @@
"default": "0", "default": "0",
"fieldname": "skip_delivery_note", "fieldname": "skip_delivery_note",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1,
"label": "Skip Delivery Note", "label": "Skip Delivery Note",
"print_hide": 1 "print_hide": 1
} }
@ -1192,7 +1193,7 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-10-14 08:46:07.540565", "modified": "2019-10-22 14:26:42.767189",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Sales Order", "name": "Sales Order",

View File

@ -204,7 +204,7 @@ class Company(NestedSet):
}) })
for default_account in default_accounts: for default_account in default_accounts:
if self.is_new() or frappe.flags.in_test: if self.is_new() or frappe.flags.in_test or frappe.flags.in_demo:
self._set_default_account(default_account, default_accounts.get(default_account)) self._set_default_account(default_account, default_accounts.get(default_account))
if not self.default_income_account: if not self.default_income_account:

View File

@ -329,8 +329,8 @@ class StockEntry(StockController):
if total_completed_qty > flt(completed_qty): if total_completed_qty > flt(completed_qty):
job_card = frappe.db.get_value('Job Card', {'operation_id': d.name}, 'name') job_card = frappe.db.get_value('Job Card', {'operation_id': d.name}, 'name')
if not job_card: if not job_card:
frappe.throw(_("Work Order {0}: job card not found for the operation {1}") frappe.throw(_("Work Order {0}: Job Card not found for the operation {1}")
.format(self.work_order, job_card)) .format(self.work_order, d.operation))
work_order_link = frappe.utils.get_link_to_form('Work Order', self.work_order) work_order_link = frappe.utils.get_link_to_form('Work Order', self.work_order)
job_card_link = frappe.utils.get_link_to_form('Job Card', job_card) job_card_link = frappe.utils.get_link_to_form('Job Card', job_card)

View File

@ -30,7 +30,7 @@ def get_total_stock(filters):
if filters.get("group_by") == "Warehouse": if filters.get("group_by") == "Warehouse":
if filters.get("company"): if filters.get("company"):
conditions += " AND warehouse.company = '%s'" % frappe.db.escape(filters.get("company"), percent=False) conditions += " AND warehouse.company = %s" % frappe.db.escape(filters.get("company"), percent=False)
conditions += " GROUP BY ledger.warehouse, item.item_code" conditions += " GROUP BY ledger.warehouse, item.item_code"
columns += "'' as company, ledger.warehouse" columns += "'' as company, ledger.warehouse"

View File

@ -2,7 +2,7 @@
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col-md-3"> <div class="col-md-3">
<div class="card-body"> <div class="card-body">
<a class="no-underline" href="{{ item.route }}"> <a class="no-underline" href="/{{ item.route }}">
<img class="website-image" src="{{ item.website_image or item.image or 'no-image.jpg' }}" alt="{{ item.item_name }}"> <img class="website-image" src="{{ item.website_image or item.image or 'no-image.jpg' }}" alt="{{ item.item_name }}">
</a> </a>
</div> </div>
@ -10,14 +10,14 @@
<div class="col-md-9"> <div class="col-md-9">
<div class="card-body"> <div class="card-body">
<h5 class="card-title"> <h5 class="card-title">
<a class="text-dark" href="{{ item.route }}"> <a class="text-dark" href="/{{ item.route }}">
{{ item.item_name or item.name }} {{ item.item_name or item.name }}
</a> </a>
</h5> </h5>
<p class="card-text"> <p class="card-text">
{{ item.website_description or item.description or '<i class="text-muted">No description</i>' }} {{ item.website_description or item.description or '<i class="text-muted">No description</i>' }}
</p> </p>
<a href="{{ item.route }}" class="btn btn-sm btn-light">{{ _('More details') }}</a> <a href="/{{ item.route }}" class="btn btn-sm btn-light">{{ _('More details') }}</a>
</div> </div>
</div> </div>
</div> </div>