Merge branch 'v12-pre-release' into version-12

This commit is contained in:
Sahil Khan 2019-10-24 17:30:19 +05:30
commit 6d9a300a85
194 changed files with 11061 additions and 11591 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

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

View File

@ -188,7 +188,6 @@
"label": "Include in gross"
},
{
"bold": 1,
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
@ -197,7 +196,7 @@
],
"icon": "fa fa-money",
"idx": 1,
"modified": "2019-08-23 03:40:58.441295",
"modified": "2019-10-10 19:10:02.967554",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",

View File

@ -20,7 +20,7 @@ frappe.ui.form.on('Bank Account', {
},
refresh: function(frm) {
frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Bank Account' }
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if (frm.doc.__islocal) {
@ -37,5 +37,9 @@ frappe.ui.form.on('Bank Account', {
});
});
}
},
is_company_account: function(frm) {
frm.set_df_property('account', 'reqd', frm.doc.is_company_account);
}
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Coupon Code', {
coupon_name:function(frm){
if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code");
}
},
coupon_type:function(frm){
if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code");
}
},
make_coupon_code: function(frm) {
var coupon_name=frm.doc.coupon_name;
var coupon_code;
if (frm.doc.coupon_type=='Gift Card') {
coupon_code=Math.random().toString(12).substring(2, 12).toUpperCase();
}
else if(frm.doc.coupon_type=='Promotional'){
coupon_name=coupon_name.replace(/\s/g,'');
coupon_code=coupon_name.toUpperCase().slice(0,8);
}
frm.doc.coupon_code=coupon_code;
frm.refresh_field('coupon_code');
},
refresh: function(frm) {
if (frm.doc.pricing_rule) {
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function(){
frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule);
});
}
}
});

View File

@ -0,0 +1,175 @@
{
"allow_import": 1,
"autoname": "field:coupon_name",
"creation": "2018-01-22 14:34:39.701832",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"coupon_name",
"coupon_type",
"customer",
"column_break_4",
"coupon_code",
"pricing_rule",
"uses",
"valid_from",
"valid_upto",
"maximum_use",
"used",
"column_break_11",
"description",
"amended_from"
],
"fields": [
{
"fieldname": "coupon_name",
"fieldtype": "Data",
"label": "Coupon Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "coupon_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Coupon Type",
"options": "Promotional\nGift Card",
"reqd": 1
},
{
"depends_on": "eval: doc.coupon_type == \"Gift Card\"",
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
"options": "Customer"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"description": "To be used to get discount",
"fieldname": "coupon_code",
"fieldtype": "Data",
"label": "Coupon Code",
"no_copy": 1,
"set_only_once": 1,
"unique": 1
},
{
"fieldname": "pricing_rule",
"fieldtype": "Link",
"label": "Pricing Rule",
"options": "Pricing Rule"
},
{
"fieldname": "uses",
"fieldtype": "Section Break",
"label": "Uses"
},
{
"fieldname": "valid_from",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Valid From"
},
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto"
},
{
"depends_on": "eval: doc.coupon_type == \"Promotional\"",
"fieldname": "maximum_use",
"fieldtype": "Int",
"label": "Maximum Use"
},
{
"default": "0",
"fieldname": "used",
"fieldtype": "Int",
"label": "Used",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Coupon Description"
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Coupon Code",
"print_hide": 1,
"read_only": 1
}
],
"modified": "2019-10-15 14:12:22.686986",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Website Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "coupon_name",
"track_changes": 1
}

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import (strip)
class CouponCode(Document):
def autoname(self):
self.coupon_name = strip(self.coupon_name)
self.name = self.coupon_name
if not self.coupon_code:
if self.coupon_type == "Promotional":
self.coupon_code =''.join([i for i in self.coupon_name if not i.isdigit()])[0:8].upper()
elif self.coupon_type == "Gift Card":
self.coupon_code = frappe.generate_hash()[:10].upper()
def validate(self):
if self.coupon_type == "Gift Card":
self.maximum_use = 1
if not self.customer:
frappe.throw(_("Please select the customer."))

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Coupon Code", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Coupon Code
() => frappe.tests.make('Coupon Code', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.get_item_details import get_item_details
from frappe.test_runner import make_test_objects
def test_create_test_data():
frappe.set_user("Administrator")
# create test item
if not frappe.db.exists("Item","_Test Tesla Car"):
item = frappe.get_doc({
"description": "_Test Tesla Car",
"doctype": "Item",
"has_batch_no": 0,
"has_serial_no": 0,
"inspection_required": 0,
"is_stock_item": 1,
"opening_stock":100,
"is_sub_contracted_item": 0,
"item_code": "_Test Tesla Car",
"item_group": "_Test Item Group",
"item_name": "_Test Tesla Car",
"apply_warehouse_wise_reorder_level": 0,
"warehouse":"_Test Warehouse - _TC",
"gst_hsn_code": "999800",
"valuation_rate": 5000,
"standard_rate":5000,
"item_defaults": [{
"company": "_Test Company",
"default_warehouse": "_Test Warehouse - _TC",
"default_price_list":"_Test Price List",
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"buying_cost_center": "_Test Cost Center - _TC",
"selling_cost_center": "_Test Cost Center - _TC",
"income_account": "Sales - _TC"
}],
"show_in_website": 1,
"route":"-test-tesla-car",
"website_warehouse": "_Test Warehouse - _TC"
})
item.insert()
# create test item price
item_price = frappe.get_list('Item Price', filters={'item_code': '_Test Tesla Car', 'price_list': '_Test Price List'}, fields=['name'])
if len(item_price)==0:
item_price = frappe.get_doc({
"doctype": "Item Price",
"item_code": "_Test Tesla Car",
"price_list": "_Test Price List",
"price_list_rate": 5000
})
item_price.insert()
# create test item pricing rule
if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
item_pricing_rule = frappe.get_doc({
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule for _Test Item",
"apply_on": "Item Code",
"items": [{
"item_code": "_Test Tesla Car"
}],
"warehouse":"_Test Warehouse - _TC",
"coupon_code_based":1,
"selling": 1,
"rate_or_discount": "Discount Percentage",
"discount_percentage": 30,
"company": "_Test Company",
"currency":"INR",
"for_price_list":"_Test Price List"
})
item_pricing_rule.insert()
# create test item sales partner
if not frappe.db.exists("Sales Partner","_Test Coupon Partner"):
sales_partner = frappe.get_doc({
"doctype": "Sales Partner",
"partner_name":"_Test Coupon Partner",
"commission_rate":2,
"referral_code": "COPART"
})
sales_partner.insert()
# create test item coupon code
if not frappe.db.exists("Coupon Code","SAVE30"):
coupon_code = frappe.get_doc({
"doctype": "Coupon Code",
"coupon_name":"SAVE30",
"coupon_code":"SAVE30",
"pricing_rule": "_Test Pricing Rule for _Test Item",
"valid_from": "2014-01-01",
"maximum_use":1,
"used":0
})
coupon_code.insert()
class TestCouponCode(unittest.TestCase):
def setUp(self):
test_create_test_data()
def tearDown(self):
frappe.set_user("Administrator")
def test_1_check_coupon_code_used_before_so(self):
coupon_code = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
# reset used coupon code count
coupon_code.used=0
coupon_code.save()
# check no coupon code is used before sales order is made
self.assertEqual(coupon_code.get("used"),0)
def test_2_sales_order_with_coupon_code(self):
so = make_sales_order(customer="_Test Customer",selling_price_list="_Test Price List",item_code="_Test Tesla Car", rate=5000,qty=1, do_not_submit=True)
so = frappe.get_doc('Sales Order', so.name)
# check item price before coupon code is applied
self.assertEqual(so.items[0].rate, 5000)
so.coupon_code='SAVE30'
so.sales_partner='_Test Coupon Partner'
so.save()
# check item price after coupon code is applied
self.assertEqual(so.items[0].rate, 3500)
so.submit()
def test_3_check_coupon_code_used_after_so(self):
doc = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
# check no coupon code is used before sales order is made
self.assertEqual(doc.get("used"),1)

View File

@ -608,15 +608,9 @@ $.extend(erpnext.journal_entry, {
},
account_query: function(frm) {
var inter_company = 0;
if (frm.doc.voucher_type == "Inter Company Journal Entry") {
inter_company = 1;
}
var filters = {
company: frm.doc.company,
is_group: 0,
inter_company_account: inter_company
is_group: 0
};
if(!frm.doc.multi_currency) {
$.extend(filters, {

View File

@ -40,7 +40,7 @@
"fields": [
{
"bold": 1,
"columns": 3,
"columns": 2,
"fieldname": "account",
"fieldtype": "Link",
"in_global_search": 1,
@ -90,14 +90,16 @@
"fieldtype": "Column Break"
},
{
"default": "Customer",
"fieldname": "party_type",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Party Type",
"options": "DocType",
"search_index": 1
},
{
"columns": 3,
"columns": 2,
"fieldname": "party",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
@ -270,7 +272,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2019-09-12 12:16:17.588399",
"modified": "2019-10-02 12:23:21.693443",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@ -940,6 +940,10 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
bank = get_default_bank_cash_account(doc.company, "Bank", mode_of_payment=doc.get("mode_of_payment"),
account=bank_account)
if not bank:
bank = get_default_bank_cash_account(doc.company, "Cash", mode_of_payment=doc.get("mode_of_payment"),
account=bank_account)
paid_amount = received_amount = 0
if party_account_currency == bank.account_currency:
paid_amount = received_amount = abs(outstanding_amount)
@ -1041,7 +1045,7 @@ def make_payment_order(source_name, target_doc=None):
def update_item(source_doc, target_doc, source_parent):
target_doc.bank_account = source_parent.party_bank_account
target_doc.amount = source_parent.base_paid_amount
target_doc.amount = source_doc.allocated_amount
target_doc.account = source_parent.paid_to
target_doc.payment_entry = source_parent.name
target_doc.supplier = source_parent.party

File diff suppressed because it is too large Load Diff

View File

@ -249,6 +249,9 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
continue
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
return item_details
if (not pricing_rule.validate_applied_rule and
pricing_rule.price_or_product_discount == "Price"):
apply_price_discount_pricing_rule(pricing_rule, item_details, args)

View File

@ -531,4 +531,32 @@ def validate_pricing_rule_for_different_cond(doc):
for d in doc.get("items"):
validate_pricing_rule_on_items(doc, d, True)
return doc
return doc
def validate_coupon_code(coupon_name):
from frappe.utils import today,getdate
coupon=frappe.get_doc("Coupon Code",coupon_name)
if coupon.valid_from:
if coupon.valid_from > getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has not started"))
elif coupon.valid_upto:
if coupon.valid_upto < getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has expired"))
elif coupon.used>=coupon.maximum_use:
frappe.throw(_("Sorry,coupon code are exhausted"))
else:
return
def update_coupon_code_count(coupon_name,transaction_type):
coupon=frappe.get_doc("Coupon Code",coupon_name)
if coupon:
if transaction_type=='used':
if coupon.used<coupon.maximum_use:
coupon.used=coupon.used+1
coupon.save(ignore_permissions=True)
else:
frappe.throw(_("{0} Coupon used are {1}. Allowed quantity is exhausted").format(coupon.coupon_code,coupon.used))
elif transaction_type=='cancelled':
if coupon.used>0:
coupon.used=coupon.used-1
coupon.save(ignore_permissions=True)

View File

@ -880,6 +880,17 @@ class PurchaseInvoice(BuyingController):
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)
list_context.update({
'show_sidebar': True,
'show_search': True,
'no_breadcrumbs': True,
'title': _('Purchase Invoices'),
})
return list_context
@frappe.whitelist()
def make_debit_note(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ frappe.ui.form.on('Share Transfer', {
};
};
});
if (frm.doc.docstatus == 1) {
if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account) {
frm.add_custom_button(__('Create Journal Entry'), function () {
erpnext.share_transfer.make_jv(frm);
});

View File

@ -12,7 +12,7 @@ from frappe.utils import (add_days, getdate, formatdate, date_diff,
from frappe.contacts.doctype.address.address import (get_address_display,
get_default_address, get_company_address)
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, InvalidAccountCurrency
from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_company_currency
@ -446,7 +446,9 @@ def validate_party_frozen_disabled(party_type, party_name):
if party_type and party_name:
if party_type in ("Customer", "Supplier"):
party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)
if party.get("is_frozen"):
if party.disabled:
frappe.throw(_("{0} {1} is disabled").format(party_type, party_name), PartyDisabled)
elif party.get("is_frozen"):
frozen_accounts_modifier = frappe.db.get_single_value( 'Accounts Settings', 'frozen_accounts_modifier')
if not frozen_accounts_modifier in frappe.get_roles():
frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen)

View File

@ -9,7 +9,7 @@
</div>
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
{% if doc.get(df.fieldname) != None -%}
{{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
{{ frappe.utils.fmt_money((doc[df.fieldname])|abs, currency=doc.currency) }}
{% endif %}
</div>
</div>
@ -26,7 +26,7 @@
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ charge.get_formatted("description") }}</label></div>
<div class="col-xs-7 text-right">
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
{{ frappe.utils.fmt_money((charge.tax_amount)|abs, currency=doc.currency) }}
</div>
</div>
{%- endif -%}
@ -65,8 +65,10 @@
{% for tdf in visible_columns %}
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
{% if tdf.fieldtype == 'Currency' %}
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}</div></td>
{% if tdf.fieldname == 'qty' %}
<div class="value">{{ (d[tdf.fieldname])|abs }}</div></td>
{% elif tdf.fieldtype == 'Currency' %}
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|abs, currency=doc.currency) }}</div></td>
{% else %}
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
{% endif %}
@ -117,7 +119,7 @@
{{ render_currency(df, doc) }}
{% elif df.fieldtype =='Table' %}
{{ render_table(df, doc)}}
{% elif doc[df.fieldname] %}
{% elif doc[df.fieldname] and df.fieldname != 'total_qty' %}
{{ render_field(df, doc) }}
{% endif %}
{% endfor %}

View File

@ -20,12 +20,7 @@ class Asset(AccountsController):
self.validate_asset_values()
self.validate_item()
self.set_missing_values()
if self.calculate_depreciation:
self.set_depreciation_rate()
self.make_depreciation_schedule()
self.set_accumulated_depreciation()
else:
self.finance_books = []
self.prepare_depreciation_data()
if self.get("schedules"):
self.validate_expected_value_after_useful_life()
@ -45,6 +40,17 @@ class Asset(AccountsController):
delete_gl_entries(voucher_type='Asset', voucher_no=self.name)
self.db_set('booked_fixed_asset', 0)
def prepare_depreciation_data(self):
if self.calculate_depreciation:
self.value_after_depreciation = 0
self.set_depreciation_rate()
self.make_depreciation_schedule()
self.set_accumulated_depreciation()
else:
self.finance_books = []
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation))
def validate_item(self):
item = frappe.get_cached_value("Item", self.item_code,
["is_fixed_asset", "is_stock_item", "disabled"], as_dict=1)

View File

@ -188,7 +188,8 @@ def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None)
idx = d.idx
break
value_after_depreciation = asset.finance_books[idx - 1].value_after_depreciation
value_after_depreciation = (asset.finance_books[idx - 1].value_after_depreciation
if asset.calculate_depreciation else asset.value_after_depreciation)
accumulated_depr_amount = flt(asset.gross_purchase_amount) - flt(value_after_depreciation)
gl_entries = [

View File

@ -16,8 +16,8 @@ frappe.query_reports["Fixed Asset Register"] = {
fieldname:"status",
label: __("Status"),
fieldtype: "Select",
options: "In Store\nDisposed",
default: 'In Store',
options: "In Location\nDisposed",
default: 'In Location',
reqd: 1
},
{

View File

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

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr
def execute(filters=None):
filters = frappe._dict(filters or {})
@ -101,7 +102,7 @@ def get_conditions(filters):
# In Store assets are those that are not sold or scrapped
operand = 'not in'
if status not in 'In Store':
if status not in 'In Location':
operand = 'in'
conditions['status'] = (operand, ['Sold', 'Scrapped'])
@ -149,12 +150,12 @@ def get_finance_book_value_map(finance_book=''):
FROM `tabAsset Finance Book`
WHERE
parentfield='finance_books'
AND finance_book=%s''', (finance_book)))
AND ifnull(finance_book, '')=%s''', cstr(finance_book)))
def get_purchase_receipt_supplier_map():
return frappe._dict(frappe.db.sql(''' Select
pr.name, pr.supplier
FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri
FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri
WHERE
pri.parent = pr.name
AND pri.is_fixed_asset=1
@ -164,7 +165,7 @@ def get_purchase_receipt_supplier_map():
def get_purchase_invoice_supplier_map():
return frappe._dict(frappe.db.sql(''' Select
pi.name, pi.supplier
FROM `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pii
FROM `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pii
WHERE
pii.parent = pi.name
AND pii.is_fixed_asset=1

View File

@ -386,7 +386,21 @@ def make_purchase_receipt(source_name, target_doc=None):
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
return get_mapped_purchase_invoice(source_name, target_doc)
@frappe.whitelist()
def make_purchase_invoice_from_portal(purchase_order_name):
doc = get_mapped_purchase_invoice(purchase_order_name, ignore_permissions=True)
if doc.contact_email != frappe.session.user:
frappe.throw(_('Not Permitted'), frappe.PermissionError)
doc.save()
frappe.db.commit()
frappe.response['type'] = 'redirect'
frappe.response.location = '/purchase-invoices/' + doc.name
def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions=False):
def postprocess(source, target):
target.flags.ignore_permissions = ignore_permissions
set_missing_values(source, target)
#Get the advance paid Journal Entries in Purchase Invoice Advance
@ -437,7 +451,8 @@ def make_purchase_invoice(source_name, target_doc=None):
"add_if_empty": True
}
doc = get_mapped_doc("Purchase Order", source_name, fields, target_doc, postprocess)
doc = get_mapped_doc("Purchase Order", source_name, fields,
target_doc, postprocess, ignore_permissions=ignore_permissions)
return doc
@ -501,6 +516,17 @@ def get_item_details(items):
return item_details
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)
list_context.update({
'show_sidebar': True,
'show_search': True,
'no_breadcrumbs': True,
'title': _('Purchase Orders'),
})
return list_context
@frappe.whitelist()
def update_status(status, name):
po = frappe.get_doc("Purchase Order", name)

View File

@ -589,6 +589,23 @@ class TestPurchaseOrder(unittest.TestCase):
frappe.db.set_value("Accounts Settings", "Accounts Settings",
"unlink_advance_payment_on_cancelation_of_order", 0)
def test_schedule_date(self):
po = create_purchase_order(do_not_submit=True)
po.schedule_date = None
po.append("items", {
"item_code": "_Test Item",
"qty": 1,
"rate": 100,
"schedule_date": add_days(nowdate(), 5)
})
po.save()
self.assertEqual(po.schedule_date, add_days(nowdate(), 1))
po.items[0].schedule_date = add_days(nowdate(), 2)
po.save()
self.assertEqual(po.schedule_date, add_days(nowdate(), 2))
def make_pr_against_po(po, received_qty=0):
pr = make_purchase_receipt(po)
pr.get("items")[0].qty = received_qty or 5

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe, unittest
from erpnext.accounts.party import get_due_date
from erpnext.exceptions import PartyDisabled
from frappe.test_runner import make_test_records
test_dependencies = ['Payment Term', 'Payment Terms Template']
@ -70,7 +71,7 @@ class TestSupplier(unittest.TestCase):
po = create_purchase_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, po.save)
self.assertRaises(PartyDisabled, po.save)
frappe.db.set_value("Supplier", "_Test Supplier", "disabled", 0)

View File

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

View File

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

View File

@ -606,8 +606,13 @@ class AccountsController(TransactionBase):
max_allowed_amt = flt(ref_amt * (100 + allowance) / 100)
if total_billed_amt < 0 and max_allowed_amt < 0:
# while making debit note against purchase return entry(purchase receipt) getting overbill error
total_billed_amt = abs(total_billed_amt)
max_allowed_amt = abs(max_allowed_amt)
if total_billed_amt - max_allowed_amt > 0.01:
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set in Stock Settings")
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
.format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
@ -1195,10 +1200,22 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
child_item.rate = flt(d.get("rate"))
if flt(child_item.price_list_rate):
discount = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
child_item.precision("discount_percentage"))
if discount > 0:
child_item.discount_percentage = discount
if flt(child_item.rate) > flt(child_item.price_list_rate):
# if rate is greater than price_list_rate, set margin
# or set discount
child_item.discount_percentage = 0
child_item.margin_type = "Amount"
child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
child_item.precision("margin_rate_or_amount"))
child_item.rate_with_margin = child_item.rate
else:
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
child_item.precision("discount_percentage"))
child_item.discount_amount = flt(
child_item.price_list_rate) - flt(child_item.rate)
child_item.margin_type = ""
child_item.margin_rate_or_amount = 0
child_item.rate_with_margin = 0
child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag:
@ -1211,6 +1228,8 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
parent.flags.ignore_validate_update_after_submit = True
parent.set_qty_as_per_stock_uom()
parent.calculate_taxes_and_totals()
if parent_doctype == "Sales Order":
parent.set_gross_profit()
frappe.get_doc('Authorization Control').validate_approving_authority(parent.doctype,
parent.company, parent.base_grand_total)

View File

@ -695,8 +695,10 @@ class BuyingController(StockController):
def validate_schedule_date(self):
if not self.get("items"):
return
if not self.schedule_date:
self.schedule_date = min([d.schedule_date for d in self.get("items")])
earliest_schedule_date = min([d.schedule_date for d in self.get("items")])
if earliest_schedule_date:
self.schedule_date = earliest_schedule_date
if self.schedule_date:
for d in self.get('items'):

View File

@ -280,22 +280,31 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
"page_len": page_len
}
having_clause = "having sum(sle.actual_qty) > 0"
if filters.get("is_return"):
having_clause = ""
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)
from `tabStock Ledger Entry` sle
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
where
batch.disabled = 0
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{0}
{match_conditions}
group by batch_no having sum(sle.actual_qty) > 0
order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
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
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
where
batch.disabled = 0
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{cond}
{match_conditions}
group by batch_no {having_clause}
order by batch.expiry_date, sle.batch_no desc
limit %(start)s, %(page_len)s""".format(
cond=cond,
match_conditions=get_match_cond(doctype),
having_clause = having_clause
), args)
return batch_nos
else:

View File

@ -37,9 +37,9 @@ status_map = {
"Sales Order": [
["Draft", None],
["To Deliver and Bill", "eval:self.per_delivered < 100 and self.per_billed < 100 and self.docstatus == 1"],
["To Bill", "eval:self.per_delivered == 100 and self.per_billed < 100 and self.docstatus == 1"],
["To Deliver", "eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1"],
["Completed", "eval:self.per_delivered == 100 and self.per_billed == 100 and self.docstatus == 1"],
["To Bill", "eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed < 100 and self.docstatus == 1"],
["To Deliver", "eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1 and not self.skip_delivery_note"],
["Completed", "eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed == 100 and self.docstatus == 1"],
["Cancelled", "eval:self.docstatus==2"],
["Closed", "eval:self.status=='Closed'"],
["On Hold", "eval:self.status=='On Hold'"],

View File

@ -140,6 +140,8 @@ def period_wise_columns_query(filters, trans):
if trans in ['Purchase Receipt', 'Delivery Note', 'Purchase Invoice', 'Sales Invoice']:
trans_date = 'posting_date'
if filters.period_based_on:
trans_date = filters.period_based_on
else:
trans_date = 'transaction_date'

View File

@ -25,7 +25,7 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p
if not filters: filters = []
if doctype == 'Supplier Quotation':
if doctype in ['Supplier Quotation', 'Purchase Invoice']:
filters.append((doctype, 'docstatus', '<', 2))
else:
filters.append((doctype, 'docstatus', '=', 1))
@ -175,4 +175,4 @@ def get_customer_field_name(doctype):
if doctype == 'Quotation':
return 'party_name'
else:
return 'customer'
return 'customer'

View File

@ -146,14 +146,7 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
@frappe.whitelist()
def make_opportunity(source_name, target_doc=None):
def set_missing_values(source, target):
address = frappe.get_all('Dynamic Link', {
'link_doctype': source.doctype,
'link_name': source.name,
'parenttype': 'Address',
}, ['parent'], limit=1)
if address:
target.customer_address = address[0].parent
_set_missing_values(source, target)
target_doc = get_mapped_doc("Lead", source_name,
{"Lead": {
@ -173,13 +166,17 @@ def make_opportunity(source_name, target_doc=None):
@frappe.whitelist()
def make_quotation(source_name, target_doc=None):
def set_missing_values(source, target):
_set_missing_values(source, target)
target_doc = get_mapped_doc("Lead", source_name,
{"Lead": {
"doctype": "Quotation",
"field_map": {
"name": "party_name"
}
}}, target_doc)
}}, target_doc, set_missing_values)
target_doc.quotation_to = "Lead"
target_doc.run_method("set_missing_values")
target_doc.run_method("set_other_charges")
@ -187,6 +184,25 @@ def make_quotation(source_name, target_doc=None):
return target_doc
def _set_missing_values(source, target):
address = frappe.get_all('Dynamic Link', {
'link_doctype': source.doctype,
'link_name': source.name,
'parenttype': 'Address',
}, ['parent'], limit=1)
contact = frappe.get_all('Dynamic Link', {
'link_doctype': source.doctype,
'link_name': source.name,
'parenttype': 'Contact',
}, ['parent'], limit=1)
if address:
target.customer_address = address[0].parent
if contact:
target.contact_person = contact[0].parent
@frappe.whitelist()
def get_lead_details(lead, posting_date=None, company=None):
if not lead: return {}

View File

@ -167,7 +167,7 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
if (me.frm.doc.opportunity_from == "Lead") {
me.frm.set_query('party_name', erpnext.queries['lead']);
}
else if (me.frm.doc.opportunity_from == "Cuatomer") {
else if (me.frm.doc.opportunity_from == "Customer") {
me.frm.set_query('party_name', erpnext.queries['customer']);
}
},

View File

@ -17,7 +17,7 @@ def get_last_interaction(contact=None, lead=None):
if link.link_doctype == 'Customer':
last_issue = get_last_issue_from_customer(link.link_name)
query_condition += "(`reference_doctype`=%s AND `reference_name`=%s) OR"
values += [link_link_doctype, link_link_name]
values += [link.link_doctype, link.link_name]
if query_condition:
# remove extra appended 'OR'

View File

@ -67,7 +67,7 @@ def get_communication_details(filters):
communication_count = None
communication_list = []
opportunities = frappe.db.get_values('Opportunity', {'opportunity_from': 'Lead'},\
['name', 'customer_name', 'lead', 'contact_email'], as_dict=1)
['name', 'customer_name', 'contact_email'], as_dict=1)
for d in opportunities:
invoice = frappe.db.sql('''

View File

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

View File

@ -73,14 +73,16 @@ def work():
make_pos_invoice()
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,
"company": erpnext.get_default_company()
})["result"] if r[2]==ref_doctype]))
outstanding_invoices = frappe.get_all(ref_doctype, fields=["name"],
filters={
"company": erpnext.get_default_company(),
"outstanding_amount": (">", 0.0)
})
# make Payment Entry
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.reference_no = random_string(6)
pe.reference_date = frappe.flags.current_date
@ -91,7 +93,7 @@ def make_payment_entries(ref_doctype, report):
# make payment via JV
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.cheque_no = random_string(6)
jv.cheque_date = frappe.flags.current_date

View File

@ -39,61 +39,4 @@ def make_project(current_date):
"doctype": "Project",
"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()

View File

@ -66,7 +66,7 @@ def make_opportunity(domain):
b = frappe.get_doc({
"doctype": "Opportunity",
"opportunity_from": "Customer",
"customer": get_random("Customer"),
"party_name": frappe.get_value("Customer", get_random("Customer"), 'name'),
"opportunity_type": "Sales",
"with_items": 1,
"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)
create_order(order, shopify_settings)
except Exception as e:
make_shopify_log(status="Error", message=e.message, exception=False)
make_shopify_log(status="Error", exception=e)
else:
make_shopify_log(status="Success")
@ -42,9 +43,9 @@ def prepare_sales_invoice(order, request_id=None):
sales_order = get_sales_order(cstr(order['id']))
if sales_order:
create_sales_invoice(order, shopify_settings, sales_order)
make_shopify_log(status="Success")
except Exception:
make_shopify_log(status="Error", exception=True)
make_shopify_log(status="Success")
except Exception as e:
make_shopify_log(status="Error", exception=e, rollback=True)
def prepare_delivery_note(order, request_id=None):
frappe.set_user('Administrator')
@ -56,8 +57,8 @@ def prepare_delivery_note(order, request_id=None):
if sales_order:
create_delivery_note(order, shopify_settings, sales_order)
make_shopify_log(status="Success")
except Exception:
make_shopify_log(status="Error", exception=True)
except Exception as e:
make_shopify_log(status="Error", exception=e, rollback=True)
def get_sales_order(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 += "\n" + ", ".join(product_not_exists)
make_shopify_log(status="Error", message=message, exception=True)
make_shopify_log(status="Error", exception=e, rollback=True)
return ''

View File

@ -12,23 +12,38 @@ class ShopifyLog(Document):
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
make_new = False
if not frappe.flags.request_id:
return
make_new = True
log = frappe.get_doc("Shopify Log", frappe.flags.request_id)
if exception:
if 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.status = status
log.save(ignore_permissions=True)
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"):
event_mapper = {
"orders/create": get_webhook_address(connector_name='shopify_connection', method="sync_sales_order", exclude_uri=True),
@ -43,11 +58,11 @@ def dump_request_data(data, event="create/order"):
}).insert(ignore_permissions=True)
frappe.db.commit()
frappe.enqueue(method=event_mapper[event], queue='short', timeout=300, is_async=True,
frappe.enqueue(method=event_mapper[event], queue='short', timeout=300, is_async=True,
**{"order": data, "request_id": log.name})
@frappe.whitelist()
def resync(method, name, request_data):
frappe.db.set_value("Shopify Log", name, "status", "Queued", update_modified=False)
frappe.enqueue(method=method, queue='short', timeout=300, is_async=True,
frappe.enqueue(method=method, queue='short', timeout=300, is_async=True,
**{"order": json.loads(request_data), "request_id": name})

View File

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

View File

@ -5,3 +5,4 @@ import frappe
class PartyFrozen(frappe.ValidationError): pass
class InvalidAccountCurrency(frappe.ValidationError): pass
class InvalidCurrency(frappe.ValidationError): pass
class PartyDisabled(frappe.ValidationError):pass

View File

@ -234,7 +234,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' \
data-pts='°C or °F' data-title='Temperature'>Temperature</a>\
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' \
data-pts='bmi' data-title='BMI'>BMI</a></div>";
data-pts='' data-title='BMI'>BMI</a></div>";
me.page.main.find(".show_chart_btns").html(show_chart_btns_html);
var data = r.message;
let labels = [], datasets = [];
@ -275,7 +275,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
datasets.push({name: "Heart Rate / Pulse", values: pulse, chartType:'line'});
datasets.push({name: "Respiratory Rate", values: respiratory_rate, chartType:'line'});
}
new Chart( ".patient_vital_charts", {
new frappe.Chart( ".patient_vital_charts", {
data: {
labels: labels,
datasets: datasets
@ -283,7 +283,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
title: title,
type: 'axis-mixed', // 'axis-mixed', 'bar', 'line', 'pie', 'percentage'
height: 150,
height: 200,
colors: ['purple', '#ffa3ef', 'light-blue'],
tooltipOptions: {

View File

@ -45,7 +45,10 @@ update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_def
leaderboards = "erpnext.startup.leaderboard.get_leaderboards"
on_session_creation = "erpnext.shopping_cart.utils.set_cart_count"
on_session_creation = [
"erpnext.portal.utils.create_customer_or_supplier",
"erpnext.shopping_cart.utils.set_cart_count"
]
on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department']
@ -102,6 +105,20 @@ website_route_rules = [
"parents": [{"label": _("Supplier Quotation"), "route": "supplier-quotations"}]
}
},
{"from_route": "/purchase-orders", "to_route": "Purchase Order"},
{"from_route": "/purchase-orders/<path:name>", "to_route": "order",
"defaults": {
"doctype": "Purchase Order",
"parents": [{"label": _("Purchase Order"), "route": "purchase-orders"}]
}
},
{"from_route": "/purchase-invoices", "to_route": "Purchase Invoice"},
{"from_route": "/purchase-invoices/<path:name>", "to_route": "order",
"defaults": {
"doctype": "Purchase Invoice",
"parents": [{"label": _("Purchase Invoice"), "route": "purchase-invoices"}]
}
},
{"from_route": "/quotations", "to_route": "Quotation"},
{"from_route": "/quotations/<path:name>", "to_route": "order",
"defaults": {
@ -148,6 +165,8 @@ standard_portal_menu_items = [
{"title": _("Projects"), "route": "/project", "reference_doctype": "Project"},
{"title": _("Request for Quotations"), "route": "/rfq", "reference_doctype": "Request for Quotation", "role": "Supplier"},
{"title": _("Supplier Quotation"), "route": "/supplier-quotations", "reference_doctype": "Supplier Quotation", "role": "Supplier"},
{"title": _("Purchase Orders"), "route": "/purchase-orders", "reference_doctype": "Purchase Order", "role": "Supplier"},
{"title": _("Purchase Invoices"), "route": "/purchase-invoices", "reference_doctype": "Purchase Invoice", "role": "Supplier"},
{"title": _("Quotations"), "route": "/quotations", "reference_doctype": "Quotation", "role":"Customer"},
{"title": _("Orders"), "route": "/orders", "reference_doctype": "Sales Order", "role":"Customer"},
{"title": _("Invoices"), "route": "/invoices", "reference_doctype": "Sales Invoice", "role":"Customer"},
@ -160,8 +179,8 @@ standard_portal_menu_items = [
{"title": _("Patient Appointment"), "route": "/patient-appointments", "reference_doctype": "Patient Appointment", "role":"Patient"},
{"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"},
{"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"},
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission"},
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application"},
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"},
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"},
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
]
@ -181,6 +200,8 @@ has_website_permission = {
"Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Supplier Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Purchase Order": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Purchase Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Material Request": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Issue": "erpnext.support.doctype.issue.issue.has_website_permission",
@ -355,52 +376,155 @@ user_privacy_documents = [
}
]
global_search_doctypes = [
{"doctype": "Customer", "index": 0},
{"doctype": "Supplier", "index": 1},
{"doctype": "Item", "index": 2},
{"doctype": "Warehouse", "index": 3},
{"doctype": "Account", "index": 4},
{"doctype": "Employee", "index": 5},
{"doctype": "BOM", "index": 6},
{"doctype": "Sales Invoice", "index": 7},
{"doctype": "Sales Order", "index": 8},
{"doctype": "Quotation", "index": 9},
{"doctype": "Work Order", "index": 10},
{"doctype": "Purchase Receipt", "index": 11},
{"doctype": "Purchase Invoice", "index": 12},
{"doctype": "Delivery Note", "index": 13},
{"doctype": "Stock Entry", "index": 14},
{"doctype": "Material Request", "index": 15},
{"doctype": "Delivery Trip", "index": 16},
{"doctype": "Pick List", "index": 17},
{"doctype": "Salary Slip", "index": 18},
{"doctype": "Leave Application", "index": 19},
{"doctype": "Expense Claim", "index": 20},
{"doctype": "Payment Entry", "index": 21},
{"doctype": "Lead", "index": 22},
{"doctype": "Opportunity", "index": 23},
{"doctype": "Item Price", "index": 24},
{"doctype": "Purchase Taxes and Charges Template", "index": 25},
{"doctype": "Sales Taxes and Charges", "index": 26},
{"doctype": "Asset", "index": 27},
{"doctype": "Project", "index": 28},
{"doctype": "Task", "index": 29},
{"doctype": "Timesheet", "index": 30},
{"doctype": "Issue", "index": 31},
{"doctype": "Serial No", "index": 32},
{"doctype": "Batch", "index": 33},
{"doctype": "Branch", "index": 34},
{"doctype": "Department", "index": 35},
{"doctype": "Employee Grade", "index": 36},
{"doctype": "Designation", "index": 37},
{"doctype": "Job Opening", "index": 38},
{"doctype": "Job Applicant", "index": 39},
{"doctype": "Job Offer", "index": 40},
{"doctype": "Salary Structure Assignment", "index": 41},
{"doctype": "Appraisal", "index": 42},
{"doctype": "Loan", "index": 43},
{"doctype": "Maintenance Schedule", "index": 44},
{"doctype": "Maintenance Visit", "index": 45},
{"doctype": "Warranty Claim", "index": 46},
]
# ERPNext doctypes for Global Search
global_search_doctypes = {
"Default": [
{"doctype": "Customer", "index": 0},
{"doctype": "Supplier", "index": 1},
{"doctype": "Item", "index": 2},
{"doctype": "Warehouse", "index": 3},
{"doctype": "Account", "index": 4},
{"doctype": "Employee", "index": 5},
{"doctype": "BOM", "index": 6},
{"doctype": "Sales Invoice", "index": 7},
{"doctype": "Sales Order", "index": 8},
{"doctype": "Quotation", "index": 9},
{"doctype": "Work Order", "index": 10},
{"doctype": "Purchase Receipt", "index": 11},
{"doctype": "Purchase Invoice", "index": 12},
{"doctype": "Delivery Note", "index": 13},
{"doctype": "Stock Entry", "index": 14},
{"doctype": "Material Request", "index": 15},
{"doctype": "Delivery Trip", "index": 16},
{"doctype": "Pick List", "index": 17},
{"doctype": "Salary Slip", "index": 18},
{"doctype": "Leave Application", "index": 19},
{"doctype": "Expense Claim", "index": 20},
{"doctype": "Payment Entry", "index": 21},
{"doctype": "Lead", "index": 22},
{"doctype": "Opportunity", "index": 23},
{"doctype": "Item Price", "index": 24},
{"doctype": "Purchase Taxes and Charges Template", "index": 25},
{"doctype": "Sales Taxes and Charges", "index": 26},
{"doctype": "Asset", "index": 27},
{"doctype": "Project", "index": 28},
{"doctype": "Task", "index": 29},
{"doctype": "Timesheet", "index": 30},
{"doctype": "Issue", "index": 31},
{"doctype": "Serial No", "index": 32},
{"doctype": "Batch", "index": 33},
{"doctype": "Branch", "index": 34},
{"doctype": "Department", "index": 35},
{"doctype": "Employee Grade", "index": 36},
{"doctype": "Designation", "index": 37},
{"doctype": "Job Opening", "index": 38},
{"doctype": "Job Applicant", "index": 39},
{"doctype": "Job Offer", "index": 40},
{"doctype": "Salary Structure Assignment", "index": 41},
{"doctype": "Appraisal", "index": 42},
{"doctype": "Loan", "index": 43},
{"doctype": "Maintenance Schedule", "index": 44},
{"doctype": "Maintenance Visit", "index": 45},
{"doctype": "Warranty Claim", "index": 46},
],
"Healthcare": [
{'doctype': 'Patient', 'index': 1},
{'doctype': 'Medical Department', 'index': 2},
{'doctype': 'Vital Signs', 'index': 3},
{'doctype': 'Healthcare Practitioner', 'index': 4},
{'doctype': 'Patient Appointment', 'index': 5},
{'doctype': 'Healthcare Service Unit', 'index': 6},
{'doctype': 'Patient Encounter', 'index': 7},
{'doctype': 'Antibiotic', 'index': 8},
{'doctype': 'Diagnosis', 'index': 9},
{'doctype': 'Lab Test', 'index': 10},
{'doctype': 'Clinical Procedure', 'index': 11},
{'doctype': 'Inpatient Record', 'index': 12},
{'doctype': 'Sample Collection', 'index': 13},
{'doctype': 'Patient Medical Record', 'index': 14},
{'doctype': 'Appointment Type', 'index': 15},
{'doctype': 'Fee Validity', 'index': 16},
{'doctype': 'Practitioner Schedule', 'index': 17},
{'doctype': 'Dosage Form', 'index': 18},
{'doctype': 'Lab Test Sample', 'index': 19},
{'doctype': 'Prescription Duration', 'index': 20},
{'doctype': 'Prescription Dosage', 'index': 21},
{'doctype': 'Sensitivity', 'index': 22},
{'doctype': 'Complaint', 'index': 23},
{'doctype': 'Medical Code', 'index': 24},
],
"Education": [
{'doctype': 'Article', 'index': 1},
{'doctype': 'Video', 'index': 2},
{'doctype': 'Topic', 'index': 3},
{'doctype': 'Course', 'index': 4},
{'doctype': 'Program', 'index': 5},
{'doctype': 'Quiz', 'index': 6},
{'doctype': 'Question', 'index': 7},
{'doctype': 'Fee Schedule', 'index': 8},
{'doctype': 'Fee Structure', 'index': 9},
{'doctype': 'Fees', 'index': 10},
{'doctype': 'Student Group', 'index': 11},
{'doctype': 'Student', 'index': 12},
{'doctype': 'Instructor', 'index': 13},
{'doctype': 'Course Activity', 'index': 14},
{'doctype': 'Quiz Activity', 'index': 15},
{'doctype': 'Course Enrollment', 'index': 16},
{'doctype': 'Program Enrollment', 'index': 17},
{'doctype': 'Student Language', 'index': 18},
{'doctype': 'Student Applicant', 'index': 19},
{'doctype': 'Assessment Result', 'index': 20},
{'doctype': 'Assessment Plan', 'index': 21},
{'doctype': 'Grading Scale', 'index': 22},
{'doctype': 'Guardian', 'index': 23},
{'doctype': 'Student Leave Application', 'index': 24},
{'doctype': 'Student Log', 'index': 25},
{'doctype': 'Room', 'index': 26},
{'doctype': 'Course Schedule', 'index': 27},
{'doctype': 'Student Attendance', 'index': 28},
{'doctype': 'Announcement', 'index': 29},
{'doctype': 'Student Category', 'index': 30},
{'doctype': 'Assessment Group', 'index': 31},
{'doctype': 'Student Batch Name', 'index': 32},
{'doctype': 'Assessment Criteria', 'index': 33},
{'doctype': 'Academic Year', 'index': 34},
{'doctype': 'Academic Term', 'index': 35},
{'doctype': 'School House', 'index': 36},
{'doctype': 'Student Admission', 'index': 37},
{'doctype': 'Fee Category', 'index': 38},
{'doctype': 'Assessment Code', 'index': 39},
{'doctype': 'Discussion', 'index': 40},
],
"Agriculture": [
{'doctype': 'Weather', 'index': 1},
{'doctype': 'Soil Texture', 'index': 2},
{'doctype': 'Water Analysis', 'index': 3},
{'doctype': 'Soil Analysis', 'index': 4},
{'doctype': 'Plant Analysis', 'index': 5},
{'doctype': 'Agriculture Analysis Criteria', 'index': 6},
{'doctype': 'Disease', 'index': 7},
{'doctype': 'Crop', 'index': 8},
{'doctype': 'Fertilizer', 'index': 9},
{'doctype': 'Crop Cycle', 'index': 10}
],
"Non Profit": [
{'doctype': 'Certified Consultant', 'index': 1},
{'doctype': 'Certification Application', 'index': 2},
{'doctype': 'Volunteer', 'index': 3},
{'doctype': 'Membership', 'index': 4},
{'doctype': 'Member', 'index': 5},
{'doctype': 'Donor', 'index': 6},
{'doctype': 'Chapter', 'index': 7},
{'doctype': 'Grant Application', 'index': 8},
{'doctype': 'Volunteer Type', 'index': 9},
{'doctype': 'Donor Type', 'index': 10},
{'doctype': 'Membership Type', 'index': 11}
],
"Hospitality": [
{'doctype': 'Hotel Room', 'index': 0},
{'doctype': 'Hotel Room Reservation', 'index': 1},
{'doctype': 'Hotel Room Pricing', 'index': 2},
{'doctype': 'Hotel Room Package', 'index': 3},
{'doctype': 'Hotel Room Type', 'index': 4}
]
}

View File

@ -1,14 +1,36 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Driver', {
frappe.ui.form.on("Driver", {
setup: function(frm) {
frm.set_query('transporter', function(){
frm.set_query("transporter", function() {
return {
filters: {
'is_transporter': 1
is_transporter: 1
}
};
});
},
refresh: function(frm) {
frm.set_query("address", function() {
return {
filters: {
is_your_company_address: !frm.doc.transporter ? 1 : 0
}
};
});
},
transporter: function(frm, cdt, cdn) {
// this assumes that supplier's address has same title as supplier's name
frappe.db
.get_doc("Address", null, { address_title: frm.doc.transporter })
.then(r => {
frappe.model.set_value(cdt, cdn, "address", r.name);
})
.catch(err => {
console.log(err);
});
}
});

View File

@ -404,8 +404,11 @@ def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day
if cint(half_day) == 1:
if from_date == to_date:
number_of_days = 0.5
else:
elif half_day_date and half_day_date <= to_date:
number_of_days = date_diff(to_date, from_date) + .5
else:
number_of_days = date_diff(to_date, from_date) + 1
else:
number_of_days = date_diff(to_date, from_date) + 1
@ -549,8 +552,16 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date):
if leave_entry.to_date > getdate(to_date):
leave_entry.to_date = to_date
half_day = 0
half_day_date = None
# fetch half day date for leaves with half days
if leave_entry.leaves % 1:
half_day = 1
half_day_date = frappe.db.get_value('Leave Application',
{'name': leave_entry.transaction_name}, ['half_day_date'])
leave_days += get_number_of_leave_days(employee, leave_type,
leave_entry.from_date, leave_entry.to_date) * -1
leave_entry.from_date, leave_entry.to_date, half_day, half_day_date) * -1
return leave_days
@ -562,7 +573,7 @@ def skip_expiry_leaves(leave_entry, date):
def get_leave_entries(employee, leave_type, from_date, to_date):
''' Returns leave entries between from_date and to_date '''
return frappe.db.sql("""
select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward
select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward, transaction_name
from `tabLeave Ledger Entry`
where employee=%(employee)s and leave_type=%(leave_type)s
and docstatus=1

View File

@ -255,16 +255,19 @@ class SalarySlip(TransactionBase):
for d in range(working_days):
dt = add_days(cstr(getdate(self.start_date)), d)
leave = frappe.db.sql("""
select t1.name, t1.half_day
from `tabLeave Application` t1, `tabLeave Type` t2
where t2.name = t1.leave_type
and t2.is_lwp = 1
and t1.docstatus = 1
and t1.employee = %(employee)s
and CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
SELECT t1.name,
CASE WHEN t1.half_day_date = %(dt)s or t1.to_date = t1.from_date
THEN t1.half_day else 0 END
FROM `tabLeave Application` t1, `tabLeave Type` t2
WHERE t2.name = t1.leave_type
AND t2.is_lwp = 1
AND t1.docstatus = 1
AND t1.employee = %(employee)s
AND CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
WHEN t2.include_holiday THEN %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
END
""".format(holidays), {"employee": self.employee, "dt": dt})
if leave:
lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
return lwp

View File

@ -4,6 +4,17 @@
frappe.provide("erpnext.maintenance");
frappe.ui.form.on('Maintenance Visit', {
refresh: function(frm) {
//filters for serial_no based on item_code
frm.set_query('serial_no', 'purposes', function(frm, cdt, cdn) {
let item = locals[cdt][cdn];
return {
filters: {
'item_code': item.item_code
}
};
});
},
setup: function(frm) {
frm.set_query('contact_person', erpnext.queries.contact_query);
frm.set_query('customer_address', erpnext.queries.address_query);

View File

@ -1,348 +1,137 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"beta": 0,
"creation": "2013-02-22 01:28:06",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"autoname": "hash",
"creation": "2013-02-22 01:28:06",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item_code",
"item_name",
"serial_no",
"description",
"work_details",
"service_person",
"work_done",
"prevdoc_doctype",
"prevdoc_docname",
"prevdoc_detail_docname"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Code",
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"permlevel": 0,
"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,
"unique": 0
},
"fetch_from": "item_code.item_name",
"fieldname": "item_name",
"fieldtype": "Data",
"in_global_search": 1,
"in_list_view": 1,
"label": "Item Name",
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Serial No",
"length": 0,
"no_copy": 0,
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "serial_no",
"fieldtype": "Link",
"label": "Serial No",
"oldfieldname": "serial_no",
"oldfieldtype": "Small Text",
"options": "Serial No"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"print_width": "300px",
"reqd": 1,
"width": "300px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "work_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "work_details",
"fieldtype": "Section Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "service_person",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Sales Person",
"length": 0,
"no_copy": 0,
"oldfieldname": "service_person",
"oldfieldtype": "Link",
"options": "Sales Person",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "service_person",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Sales Person",
"oldfieldname": "service_person",
"oldfieldtype": "Link",
"options": "Sales Person",
"reqd": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "work_done",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Work Done",
"length": 0,
"no_copy": 0,
"oldfieldname": "work_done",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "work_done",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Work Done",
"oldfieldname": "work_done",
"oldfieldtype": "Small Text",
"reqd": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevdoc_doctype",
"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": "Document Type",
"length": 0,
"no_copy": 1,
"oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data",
"options": "DocType",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "prevdoc_doctype",
"fieldtype": "Link",
"label": "Document Type",
"no_copy": 1,
"oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data",
"options": "DocType",
"print_hide": 1,
"print_width": "150px",
"read_only": 1,
"report_hide": 1,
"width": "150px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevdoc_docname",
"fieldtype": "Dynamic 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": "Against Document No",
"length": 0,
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data",
"options": "prevdoc_doctype",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "160px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "prevdoc_docname",
"fieldtype": "Dynamic Link",
"label": "Against Document No",
"no_copy": 1,
"oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data",
"options": "prevdoc_doctype",
"print_hide": 1,
"print_width": "160px",
"read_only": 1,
"report_hide": 1,
"width": "160px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevdoc_detail_docname",
"fieldtype": "Data",
"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": "Against Document Detail No",
"length": 0,
"no_copy": 1,
"oldfieldname": "prevdoc_detail_docname",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "160px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "prevdoc_detail_docname",
"fieldtype": "Data",
"hidden": 1,
"label": "Against Document Detail No",
"no_copy": 1,
"oldfieldname": "prevdoc_detail_docname",
"oldfieldtype": "Data",
"print_hide": 1,
"print_width": "160px",
"read_only": 1,
"report_hide": 1,
"width": "160px"
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-17 17:06:11.910266",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Visit Purpose",
"owner": "ashwini@webnotestech.com",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 1,
"track_seen": 0
],
"idx": 1,
"istable": 1,
"modified": "2019-10-03 14:55:52.786805",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance Visit Purpose",
"owner": "ashwini@webnotestech.com",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -12,6 +12,7 @@ frappe.ui.form.on('Blanket Order', {
},
refresh: function(frm) {
erpnext.hide_company();
if (frm.doc.customer && frm.doc.docstatus === 1) {
frm.add_custom_button(__('View Orders'), function() {
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) {
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() {
return { filters: { selling: 1 } };
});
}
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() {
return { filters: { buying: 1 } };
});

View File

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

View File

@ -4,13 +4,21 @@
from __future__ import unicode_literals
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.mapper import get_mapped_doc
from erpnext.stock.doctype.item.item import get_item_defaults
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):
ref_doctype = "Sales Order" if self.blanket_order_type == "Selling" else "Purchase Order"
item_ordered_qty = frappe._dict(frappe.db.sql("""

View File

@ -117,7 +117,7 @@ frappe.ui.form.on("BOM", {
args: {
update_parent: true,
from_child_bom:false,
save: false
save: frm.doc.docstatus === 1 ? true : false
},
callback: function(r) {
refresh_field("items");

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
# 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
names = [cint(name.split('-')[-1]) for name in names]
@ -173,7 +174,7 @@ class BOM(WebsiteGenerator):
#Customer Provided parts will have zero rate
if not frappe.db.get_value('Item', arg["item_code"], 'is_customer_provided_item'):
if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom:
rate = self.get_bom_unitcost(arg['bom_no']) * (arg.get("conversion_factor") or 1)
rate = flt(self.get_bom_unitcost(arg['bom_no'])) * (arg.get("conversion_factor") or 1)
else:
if self.rm_cost_as_per == 'Valuation Rate':
rate = self.get_valuation_rate(arg) * (arg.get("conversion_factor") or 1)

View File

@ -558,7 +558,7 @@ def get_sales_orders(self):
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
select distinct so.name, so.transaction_date, so.customer, so.base_grand_total as grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")

View File

@ -91,6 +91,16 @@ frappe.ui.form.on("Work Order", {
};
});
frm.set_query("operation", "required_items", function() {
return {
query: "erpnext.manufacturing.doctype.work_order.work_order.get_bom_operations",
filters: {
'parent': frm.doc.bom_no,
'parenttype': 'BOM'
}
};
});
// formatter for work order operation
frm.set_indicator_formatter('operation',
function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange"; });

View File

@ -64,7 +64,8 @@ class WorkOrder(Document):
from `tabSales Order` so
inner join `tabSales Order Item` so_item on so_item.parent = so.name
left join `tabProduct Bundle Item` pk_item on so_item.item_code = pk_item.parent
where so.name=%s and so.docstatus = 1 and (
where so.name=%s and so.docstatus = 1
and so.skip_delivery_note = 0 and (
so_item.item_code=%s or
pk_item.item_code=%s )
""", (self.sales_order, self.production_item, self.production_item), as_dict=1)
@ -78,6 +79,7 @@ class WorkOrder(Document):
where so.name=%s
and so.name=so_item.parent
and so.name=packed_item.parent
and so.skip_delivery_note = 0
and so_item.item_code = packed_item.parent_item
and so.docstatus = 1 and packed_item.item_code=%s
""", (self.sales_order, self.production_item), as_dict=1)
@ -477,6 +479,9 @@ class WorkOrder(Document):
'include_item_in_manufacturing': item.include_item_in_manufacturing
})
if not self.project:
self.project = item.get("project")
self.set_available_qty()
def update_transaferred_qty_for_required_items(self):
@ -543,6 +548,13 @@ class WorkOrder(Document):
bom.set_bom_material_details()
return bom
def get_bom_operations(doctype, txt, searchfield, start, page_len, filters):
if txt:
filters['operation'] = ('like', '%%%s%%' % txt)
return frappe.get_all('BOM Operation',
filters = filters, fields = ['operation'], as_list=1)
@frappe.whitelist()
def get_item_details(item, project = None):
res = frappe.db.sql("""

View File

@ -10,6 +10,7 @@ def execute():
for last allocation """
frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
frappe.reload_doc("HR", "doctype", "Leave Encashment")
frappe.reload_doc("HR", "doctype", "Leave Type")
if frappe.db.a_row_exists("Leave Ledger Entry"):
return
@ -84,4 +85,4 @@ def get_leaves_application_records():
def get_leave_encashment_records():
return frappe.get_all("Leave Encashment", filters={
"docstatus": 1
}, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
}, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])

View File

@ -41,7 +41,9 @@ def execute():
item = frappe.get_doc("Item", item_code)
item.set("taxes", [])
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""})
item.save()
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
for d in item.taxes:
d.db_insert()
doctypes = [
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',

View File

@ -1,5 +1,8 @@
from __future__ import unicode_literals
import frappe
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
from erpnext.shopping_cart.cart import get_debtors_account
from frappe.utils.nestedset import get_root_of
def set_default_role(doc, method):
'''Set customer, supplier, student, guardian based on email'''
@ -21,3 +24,88 @@ def set_default_role(doc, method):
doc.add_roles('Student')
elif frappe.get_value('Guardian', dict(email_address=doc.email)) and 'Guardian' not in roles:
doc.add_roles('Guardian')
def create_customer_or_supplier():
'''Based on the default Role (Customer, Supplier), create a Customer / Supplier.
Called on_session_creation hook.
'''
user = frappe.session.user
if frappe.db.get_value('User', user, 'user_type') != 'Website User':
return
user_roles = frappe.get_roles()
portal_settings = frappe.get_single('Portal Settings')
default_role = portal_settings.default_role
if default_role not in ['Customer', 'Supplier']:
return
# create customer / supplier if the user has that role
if portal_settings.default_role and portal_settings.default_role in user_roles:
doctype = portal_settings.default_role
else:
doctype = None
if not doctype:
return
if party_exists(doctype, user):
return
party = frappe.new_doc(doctype)
fullname = frappe.utils.get_fullname(user)
if doctype == 'Customer':
cart_settings = get_shopping_cart_settings()
if cart_settings.enable_checkout:
debtors_account = get_debtors_account(cart_settings)
else:
debtors_account = ''
party.update({
"customer_name": fullname,
"customer_type": "Individual",
"customer_group": cart_settings.default_customer_group,
"territory": get_root_of("Territory")
})
if debtors_account:
party.update({
"accounts": [{
"company": cart_settings.company,
"account": debtors_account
}]
})
else:
party.update({
"supplier_name": fullname,
"supplier_group": "All Supplier Groups",
"supplier_type": "Individual"
})
party.flags.ignore_mandatory = True
party.insert(ignore_permissions=True)
contact = frappe.new_doc("Contact")
contact.update({
"first_name": fullname,
"email_id": user
})
contact.append('links', dict(link_doctype=doctype, link_name=party.name))
contact.flags.ignore_mandatory = True
contact.insert(ignore_permissions=True)
return party
def party_exists(doctype, user):
contact_name = frappe.db.get_value("Contact", {"email_id": user})
if contact_name:
contact = frappe.get_doc('Contact', contact_name)
doctypes = [d.link_doctype for d in contact.links]
return doctype in doctypes
return False

View File

@ -1233,7 +1233,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
"is_return": cint(me.frm.doc.is_return),
"update_stock": in_list(['Sales Invoice', 'Purchase Invoice'], me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0,
"conversion_factor": me.frm.doc.conversion_factor,
"pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : ''
"pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '',
"coupon_code": me.frm.doc.coupon_code
};
},
@ -1652,6 +1653,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
'item_code': item.item_code,
'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;
return {
@ -1742,6 +1748,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
});
}
},
coupon_code: function() {
var me = this;
frappe.run_serially([
() => this.frm.doc.ignore_pricing_rule=1,
() => me.ignore_pricing_rule(),
() => this.frm.doc.ignore_pricing_rule=0,
() => me.apply_pricing_rule()
]);
}
});

View File

@ -5,6 +5,19 @@
frappe.provide("erpnext.shopping_cart");
var shopping_cart = erpnext.shopping_cart;
var getParams = function (url) {
var params = [];
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
};
frappe.ready(function() {
var full_name = frappe.session && frappe.session.user_fullname;
// update user
@ -12,7 +25,32 @@ frappe.ready(function() {
$('.navbar li[data-label="User"] a')
.html('<i class="fa fa-fixed-width fa fa-user"></i> ' + full_name);
}
// set coupon code and sales partner code
var url_args = getParams(window.location.href);
var referral_coupon_code = url_args['cc'];
var referral_sales_partner = url_args['sp'];
var d = new Date();
// expires within 30 minutes
d.setTime(d.getTime() + (0.02 * 24 * 60 * 60 * 1000));
var expires = "expires="+d.toUTCString();
if (referral_coupon_code) {
document.cookie = "referral_coupon_code=" + referral_coupon_code + ";" + expires + ";path=/";
}
if (referral_sales_partner) {
document.cookie = "referral_sales_partner=" + referral_sales_partner + ";" + expires + ";path=/";
}
referral_coupon_code=frappe.get_cookie("referral_coupon_code");
referral_sales_partner=frappe.get_cookie("referral_sales_partner");
if (referral_coupon_code && $(".tot_quotation_discount").val()==undefined ) {
$(".txtcoupon").val(referral_coupon_code);
}
if (referral_sales_partner) {
$(".txtreferral_sales_partner").val(referral_sales_partner);
}
// update login
shopping_cart.show_shoppingcart_dropdown();
shopping_cart.set_cart_count();

View File

@ -51,3 +51,30 @@
width: 24px;
height: 24px;
}
.website-list .result {
margin-top: 2rem;
}
.result {
border-bottom: 1px solid $border-color;
}
.transaction-list-item {
padding: 1rem 0;
border-top: 1px solid $border-color;
position: relative;
a.transaction-item-link {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-decoration: none;
opacity: 0;
overflow: hidden;
text-indent: -9999px;
z-index: 0;
}
}

View File

@ -0,0 +1,8 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('DATEV Settings', {
// refresh: function(frm) {
// }
});

View File

@ -0,0 +1,105 @@
{
"autoname": "field:client",
"creation": "2019-08-13 23:56:34.259906",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"client",
"column_break_2",
"client_number",
"section_break_4",
"consultant",
"column_break_6",
"consultant_number"
],
"fields": [
{
"fieldname": "client",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Client",
"options": "Company",
"reqd": 1,
"unique": 1
},
{
"fieldname": "client_number",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Client ID",
"reqd": 1
},
{
"fieldname": "consultant",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Consultant",
"options": "Supplier"
},
{
"fieldname": "consultant_number",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Consultant ID",
"reqd": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
}
],
"modified": "2019-08-14 00:03:26.616460",
"modified_by": "Administrator",
"module": "Regional",
"name": "DATEV Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class DATEVSettings(Document):
pass

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestDATEVSettings(unittest.TestCase):
pass

View File

@ -1,6 +1,6 @@
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>
{% if gst_state %}{{ gst_state }}{% endif -%},
{% if gst_state_number %}State Code: {{ gst_state_number }}<br>{% endif -%}
{% if gst_state %}{{ gst_state }}{% endif -%}
{% if gst_state_number %}, State Code: {{ gst_state_number }}<br>{% endif -%}
{% if pincode %}PIN: {{ pincode }}<br>{% endif -%}
{{ country }}<br>
{% if phone %}Phone: {{ phone }}<br>{% endif -%}

View File

@ -19,7 +19,7 @@
{%- endmacro %}
{%- macro render_discount_or_margin(item) -%}
{%- if item.discount_percentage > 0.0 or item.margin_type %}
{%- if (item.discount_percentage and item.discount_percentage > 0.0) or item.margin_type %}
<ScontoMaggiorazione>
{%- if item.discount_percentage > 0.0 %}
<Tipo>SC</Tipo>

View File

@ -151,8 +151,7 @@ def get_invoice_summary(items, taxes):
tax_rate=tax.rate,
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount,
taxable_amount=(reference_row.tax_amount if tax.charge_type == 'On Previous Row Amount'
else reference_row.total),
taxable_amount=reference_row.tax_amount,
item_tax_rate={tax.account_head: tax.rate},
charges=True
)
@ -177,6 +176,10 @@ def get_invoice_summary(items, taxes):
summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason
summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law
if summary_data.get("0.0") and tax.charge_type in ["On Previous Row Total",
"On Previous Row Amount"]:
summary_data[key]["taxable_amount"] = tax.total
if summary_data == {}: #Implies that Zero VAT has not been set on any item.
summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total,
"tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law})

View File

@ -8,6 +8,7 @@ Provide a report and downloadable CSV according to the German DATEV format.
all required columns. Used to import the data into the DATEV Software.
"""
from __future__ import unicode_literals
import datetime
import json
from six import string_types
import frappe
@ -17,24 +18,28 @@ import pandas as pd
def execute(filters=None):
"""Entry point for frappe."""
validate_filters(filters)
validate(filters)
result = get_gl_entries(filters, as_dict=0)
columns = get_columns()
return columns, result
def validate_filters(filters):
"""Make sure all mandatory filters are present."""
def validate(filters):
"""Make sure all mandatory filters and settings are present."""
if not filters.get('company'):
frappe.throw(_('{0} is mandatory').format(_('Company')))
frappe.throw(_('<b>Company</b> is a mandatory filter.'))
if not filters.get('from_date'):
frappe.throw(_('{0} is mandatory').format(_('From Date')))
frappe.throw(_('<b>From Date</b> is a mandatory filter.'))
if not filters.get('to_date'):
frappe.throw(_('{0} is mandatory').format(_('To Date')))
frappe.throw(_('<b>To Date</b> is a mandatory filter.'))
try:
frappe.get_doc('DATEV Settings', filters.get('company'))
except frappe.DoesNotExistError:
frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
def get_columns():
"""Return the list of columns that will be shown in query report."""
@ -158,13 +163,84 @@ def get_gl_entries(filters, as_dict):
return gl_entries
def get_datev_csv(data):
def get_datev_csv(data, filters):
"""
Fill in missing columns and return a CSV in DATEV Format.
For automatic processing, DATEV requires the first line of the CSV file to
hold meta data such as the length of account numbers oder the category of
the data.
Arguments:
data -- array of dictionaries
filters -- dict
"""
header = [
# A = DATEV format
# DTVF = created by DATEV software,
# EXTF = created by other software
"EXTF",
# B = version of the DATEV format
# 141 = 1.41,
# 510 = 5.10,
# 720 = 7.20
"510",
# C = Data category
# 21 = Transaction batch (Buchungsstapel),
# 67 = Buchungstextkonstanten,
# 16 = Debitors/Creditors,
# 20 = Account names (Kontenbeschriftungen)
"21",
# D = Format name
# Buchungsstapel,
# Buchungstextkonstanten,
# Debitoren/Kreditoren,
# Kontenbeschriftungen
"Buchungsstapel",
# E = Format version (regarding format name)
"",
# F = Generated on
datetime.datetime.now().strftime("%Y%m%d"),
# G = Imported on -- stays empty
"",
# H = Origin (SV = other (?), RE = KARE)
"SV",
# I = Exported by
frappe.session.user,
# J = Imported by -- stays empty
"",
# K = Tax consultant number (Beraternummer)
frappe.get_value("DATEV Settings", filters.get("company"), "consultant_number") or "",
"",
# L = Tax client number (Mandantennummer)
frappe.get_value("DATEV Settings", filters.get("company"), "client_number") or "",
"",
# M = Start of the fiscal year (Wirtschaftsjahresbeginn)
frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"),
# N = Length of account numbers (Sachkontenlänge)
"4",
# O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"),
# P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions")
"{} - {} Buchungsstapel".format(
frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy")
),
# R = Diktatkürzel
"",
# S = Buchungstyp
# 1 = Transaction batch (Buchungsstapel),
# 2 = Annual financial statement (Jahresabschluss)
"1",
# T = Rechnungslegungszweck
"",
# U = Festschreibung
"",
# V = Kontoführungs-Währungskennzeichen des Geldkontos
frappe.get_value("Company", filters.get("company"), "default_currency")
]
columns = [
# All possible columns must tbe listed here, because DATEV requires them to
# be present in the CSV.
@ -324,9 +400,10 @@ def get_datev_csv(data):
data_df = pd.DataFrame.from_records(data)
result = empty_df.append(data_df)
result["Belegdatum"] = pd.to_datetime(result["Belegdatum"])
result['Belegdatum'] = pd.to_datetime(result['Belegdatum'])
return result.to_csv(
header = ';'.join(header).encode('latin_1')
data = result.to_csv(
sep=b';',
# European decimal seperator
decimal=',',
@ -342,6 +419,7 @@ def get_datev_csv(data):
columns=columns
)
return header + b'\r\n' + data
@frappe.whitelist()
def download_datev_csv(filters=None):
@ -359,15 +437,9 @@ def download_datev_csv(filters=None):
if isinstance(filters, string_types):
filters = json.loads(filters)
validate_filters(filters)
validate(filters)
data = get_gl_entries(filters, as_dict=1)
filename = 'DATEV_Buchungsstapel_{}-{}_bis_{}'.format(
filters.get('company'),
filters.get('from_date'),
filters.get('to_date')
)
frappe.response['result'] = get_datev_csv(data)
frappe.response['doctype'] = filename
frappe.response['result'] = get_datev_csv(data, filters)
frappe.response['doctype'] = 'EXTF_Buchungsstapel'
frappe.response['type'] = 'csv'

View File

@ -8,7 +8,7 @@ import unittest
from erpnext.accounts.party import get_due_date
from frappe.test_runner import make_test_records
from erpnext.exceptions import PartyFrozen
from erpnext.exceptions import PartyFrozen, PartyDisabled
from frappe.utils import flt
from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
from erpnext.tests.utils import create_test_contact_and_address
@ -178,7 +178,7 @@ class TestCustomer(unittest.TestCase):
so = make_sales_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, so.save)
self.assertRaises(PartyDisabled, so.save)
frappe.db.set_value("Customer", "_Test Customer", "disabled", 0)

View File

@ -1904,7 +1904,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Additional Discount",
"label": "Additional Discount and Coupon Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -1920,6 +1920,74 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "coupon_code",
"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": "Coupon Code",
"length": 0,
"no_copy": 0,
"options": "Coupon Code",
"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,
"fetch_if_empty": 0,
"fieldname": "referral_sales_partner",
"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": "Referral Sales Partner",
"length": 0,
"no_copy": 0,
"options": "Sales Partner",
"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,
@ -3263,7 +3331,7 @@
"istable": 0,
"max_attachments": 1,
"menu_index": 0,
"modified": "2019-06-26 01:00:21.545591",
"modified": "2019-10-14 01:00:21.545591",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",

View File

@ -142,6 +142,9 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
if customer:
target.customer = customer.name
target.customer_name = customer.customer_name
if source.referral_sales_partner:
target.sales_partner=source.referral_sales_partner
target.commission_rate=frappe.get_value('Sales Partner', source.referral_sales_partner, 'commission_rate')
target.ignore_pricing_rule = 1
target.flags.ignore_permissions = ignore_permissions
target.run_method("set_missing_values")

View File

@ -136,7 +136,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
if(doc.status !== 'Closed') {
if(doc.status !== 'On Hold') {
allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
&& !this.frm.doc.skip_delivery_note
if (this.frm.has_perm("submit")) {
if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
@ -341,7 +342,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
},
order_type: function() {
this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
this.toggle_delivery_date();
},
tc_name: function() {
@ -355,6 +356,15 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
})
},
skip_delivery_note: function() {
this.toggle_delivery_date();
},
toggle_delivery_date: function() {
this.frm.fields_dict.items.grid.toggle_reqd("delivery_date",
(this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note));
},
make_raw_material_request: function() {
var me = this;
this.frm.call({

View File

@ -14,6 +14,7 @@
"customer",
"customer_name",
"order_type",
"skip_delivery_note",
"column_break1",
"amended_from",
"company",
@ -78,6 +79,7 @@
"loyalty_points",
"loyalty_amount",
"section_break_48",
"coupon_code",
"apply_discount_on",
"base_discount_amount",
"column_break_50",
@ -252,6 +254,7 @@
},
{
"allow_on_submit": 1,
"depends_on": "eval:!doc.skip_delivery_note",
"fieldname": "delivery_date",
"fieldtype": "Date",
"in_list_view": 1,
@ -676,7 +679,13 @@
"collapsible_depends_on": "discount_amount",
"fieldname": "section_break_48",
"fieldtype": "Section Break",
"label": "Additional Discount"
"label": "Additional Discount and Coupon Code"
},
{
"fieldname": "coupon_code",
"fieldtype": "Link",
"label": "Coupon Code",
"options": "Coupon Code"
},
{
"default": "Grand Total",
@ -941,7 +950,7 @@
"collapsible": 1,
"fieldname": "printing_details",
"fieldtype": "Section Break",
"label": "Printing Details"
"label": "Print Settings"
},
{
"fieldname": "language",
@ -1023,7 +1032,7 @@
"print_hide": 1
},
{
"depends_on": "eval:!doc.__islocal",
"depends_on": "eval:!doc.__islocal && !doc.skip_delivery_note_creation",
"description": "% of materials delivered against this Sales Order",
"fieldname": "per_delivered",
"fieldtype": "Percent",
@ -1120,7 +1129,7 @@
"allow_on_submit": 1,
"fieldname": "sales_team",
"fieldtype": "Table",
"label": "Sales Team1",
"label": "Sales Team",
"oldfieldname": "sales_team",
"oldfieldtype": "Table",
"options": "Sales Team",
@ -1171,12 +1180,20 @@
"fieldtype": "Data",
"label": "Phone",
"read_only": 1
},
{
"default": "0",
"fieldname": "skip_delivery_note",
"fieldtype": "Check",
"hidden": 1,
"label": "Skip Delivery Note",
"print_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"modified": "2019-09-12 02:13:56.308839",
"modified": "2019-10-22 14:26:42.767189",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",

View File

@ -46,6 +46,10 @@ class SalesOrder(SellingController):
self.validate_serial_no_based_delivery()
validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
validate_coupon_code(self.coupon_code)
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
make_packing_list(self)
@ -57,13 +61,13 @@ class SalesOrder(SellingController):
def validate_po(self):
# validate p.o date v/s delivery date
if self.po_date:
if self.po_date and not self.skip_delivery_note:
for d in self.get("items"):
if d.delivery_date and getdate(self.po_date) > getdate(d.delivery_date):
frappe.throw(_("Row #{0}: Expected Delivery Date cannot be before Purchase Order Date")
.format(d.idx))
if self.po_no and self.customer:
if self.po_no and self.customer and not self.skip_delivery_note:
so = frappe.db.sql("select name from `tabSales Order` \
where ifnull(po_no, '') = %s and name != %s and docstatus < 2\
and customer = %s", (self.po_no, self.name, self.customer))
@ -100,7 +104,7 @@ class SalesOrder(SellingController):
super(SalesOrder, self).validate_order_type()
def validate_delivery_date(self):
if self.order_type == 'Sales':
if self.order_type == 'Sales' and not self.skip_delivery_note:
delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date]
max_delivery_date = max(delivery_date_list) if delivery_date_list else None
if not self.delivery_date:
@ -177,6 +181,9 @@ class SalesOrder(SellingController):
self.update_blanket_order()
update_linked_doc(self.doctype, self.name, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
update_coupon_code_count(self.coupon_code,'used')
def on_cancel(self):
super(SalesOrder, self).on_cancel()
@ -195,7 +202,10 @@ class SalesOrder(SellingController):
self.update_blanket_order()
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
update_coupon_code_count(self.coupon_code,'cancelled')
def update_project(self):
if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') != "Each Transaction":
return
@ -760,6 +770,7 @@ def get_events(start, end, filters=None):
from
`tabSales Order`, `tabSales Order Item`
where `tabSales Order`.name = `tabSales Order Item`.parent
and `tabSales Order`.skip_delivery_note = 0
and (ifnull(`tabSales Order Item`.delivery_date, '0000-00-00')!= '0000-00-00') \
and (`tabSales Order Item`.delivery_date between %(start)s and %(end)s)
and `tabSales Order`.docstatus < 2

View File

@ -1,58 +1,41 @@
frappe.listview_settings['Sales Order'] = {
add_fields: ["base_grand_total", "customer_name", "currency", "delivery_date",
"per_delivered", "per_billed", "status", "order_type", "name"],
"per_delivered", "per_billed", "status", "order_type", "name", "skip_delivery_note"],
get_indicator: function (doc) {
if (doc.status === "Closed") {
// Closed
return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.status === "On Hold") {
// on hold
return [__("On Hold"), "orange", "status,=,On Hold"];
} else if (doc.order_type !== "Maintenance"
&& flt(doc.per_delivered, 6) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) {
} else if (doc.status === "Completed") {
return [__("Completed"), "green", "status,=,Completed"];
} else if (!doc.skip_delivery_note && flt(doc.per_delivered, 6) < 100) {
if (frappe.datetime.get_diff(doc.delivery_date) < 0) {
// not delivered & overdue
return [__("Overdue"), "red", "per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"];
} else if (doc.order_type !== "Maintenance"
&& flt(doc.per_delivered, 6) < 100 && doc.status !== "Closed") {
// not delivered
if (flt(doc.grand_total) === 0) {
return [__("Overdue"), "red",
"per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"];
} else if (flt(doc.grand_total) === 0) {
// not delivered (zero-amount order)
return [__("To Deliver"), "orange",
"per_delivered,<,100|grand_total,=,0|status,!=,Closed"];
} else if (flt(doc.per_billed, 6) < 100) {
// not delivered & not billed
return [__("To Deliver and Bill"), "orange",
"per_delivered,<,100|per_billed,<,100|status,!=,Closed"];
} else {
// not billed
return [__("To Deliver"), "orange",
"per_delivered,<,100|per_billed,=,100|status,!=,Closed"];
}
} else if ((flt(doc.per_delivered, 6) === 100)
&& flt(doc.grand_total) !== 0 && flt(doc.per_billed, 6) < 100 && doc.status !== "Closed") {
} else if ((flt(doc.per_delivered, 6) === 100) && flt(doc.grand_total) !== 0
&& flt(doc.per_billed, 6) < 100) {
// to bill
return [__("To Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Closed"];
} else if ((flt(doc.per_delivered, 6) === 100)
&& (flt(doc.grand_total) === 0 || flt(doc.per_billed, 6) == 100) && doc.status !== "Closed") {
return [__("Completed"), "green", "per_delivered,=,100|per_billed,=,100|status,!=,Closed"];
}else if (doc.order_type === "Maintenance" && flt(doc.per_delivered, 6) < 100 && doc.status !== "Closed"){
if(flt(doc.per_billed, 6) < 100 ){
return [__("To Deliver and Bill"), "orange", "per_delivered,=,100|per_billed,<,100|status,!=,Closed"];
}else if(flt(doc.per_billed, 6) === 100){
return [__("To Deliver"), "orange", "per_delivered,=,100|per_billed,=,100|status,!=,Closed"];
}
return [__("To Bill"), "orange",
"per_delivered,=,100|per_billed,<,100|status,!=,Closed"];
} else if (doc.skip_delivery_note && flt(doc.per_billed, 6) < 100){
return [__("To Bill"), "orange", "per_billed,<,100|status,!=,Closed"];
}
},
onload: function(listview) {
var method = "erpnext.selling.doctype.sales_order.sales_order.close_or_unclose_sales_orders";

View File

@ -149,6 +149,7 @@
},
{
"columns": 2,
"depends_on": "eval: !parent.skip_delivery_note",
"fieldname": "delivery_date",
"fieldtype": "Date",
"in_list_view": 1,
@ -693,6 +694,7 @@
"description": "For Production",
"fieldname": "produced_qty",
"fieldtype": "Float",
"hidden": 1,
"label": "Produced Quantity",
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
@ -743,7 +745,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2019-09-13 12:18:54.903107",
"modified": "2019-10-10 08:46:26.244823",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",

View File

@ -80,10 +80,14 @@ frappe.query_reports["Sales Analytics"] = {
var tree_type = frappe.query_report.filters[0].value;
if(tree_type == "Customer" || tree_type == "Item") {
if(tree_type == "Customer") {
row_values = data.slice(4,length-1).map(function (column) {
return column.content;
})
} else if (tree_type == "Item") {
row_values = data.slice(5,length-1).map(function (column) {
return column.content;
})
}
else {
row_values = data.slice(3,length-1).map(function (column) {

View File

@ -136,7 +136,7 @@ class Analytics(object):
if self.filters["value_quantity"] == 'Value':
value_field = 'base_amount'
else:
value_field = 'qty'
value_field = 'stock_qty'
self.entries = frappe.db.sql("""
select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
@ -338,8 +338,10 @@ class Analytics(object):
def get_chart_data(self):
length = len(self.columns)
if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
if self.filters.tree_type in ["Customer", "Supplier"]:
labels = [d.get("label") for d in self.columns[2:length - 1]]
elif self.filters.tree_type == "Item":
labels = [d.get("label") for d in self.columns[3:length - 1]]
else:
labels = [d.get("label") for d in self.columns[1:length - 1]]
self.chart = {

View File

@ -204,7 +204,7 @@ class Company(NestedSet):
})
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))
if not self.default_income_account:

View File

@ -24,5 +24,11 @@ frappe.ui.form.on('Sales Partner', {
}
}
};
},
referral_code:function(frm){
if (frm.doc.referral_code) {
frm.doc.referral_code=frm.doc.referral_code.toUpperCase();
frm.refresh_field('referral_code');
}
}
});

View File

@ -510,6 +510,73 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_16",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "To Track inbound purchase",
"fetch_if_empty": 0,
"fieldname": "referral_code",
"fieldtype": "Data",
"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": "Referral Code",
"length": 8,
"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": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -779,7 +846,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-21 16:26:45.447265",
"modified": "2019-10-14 16:26:45.447265",
"modified_by": "Administrator",
"module": "Setup",
"name": "Sales Partner",

View File

@ -65,7 +65,7 @@ def install(country=None):
{'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'),
'allow_encashment': 1, 'is_carry_forward': 1, 'max_continuous_days_allowed': '3', 'include_holiday': 1},
{'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'),
'allow_encashment': 0, 'is_carry_forward': 0, 'include_holiday': 1},
'allow_encashment': 0, 'is_carry_forward': 0, 'include_holiday': 1, 'is_compensatory':1 },
{'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'),
'allow_encashment': 0, 'is_carry_forward': 0, 'include_holiday': 1},
{'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'),

View File

@ -65,7 +65,12 @@ def get_setup_stages(args=None):
'fn': stage_four,
'args': args,
'fail_msg': _("Failed to create website")
}
},
{
'fn': set_active_domains,
'args': args,
'fail_msg': _("Failed to add Domain")
},
]
},
{
@ -128,3 +133,7 @@ def setup_complete(args=None):
setup_defaults(args)
stage_four(args)
fin(args)
def set_active_domains(args):
domain_settings = frappe.get_single('Domain Settings')
domain_settings.set_active_domains(args.get('domains'))

Some files were not shown because too many files have changed in this diff Show More