Compare commits

..

33 Commits

Author SHA1 Message Date
Frappe PR Bot
f3f6d35a84 chore(release): Bumped to Version 13.42.0
# [13.42.0](https://github.com/frappe/erpnext/compare/v13.41.1...v13.42.0) (2022-11-15)

### Bug Fixes

* add Document Date in E-Invoice print format ([a16347f](a16347f325))
* ambiguous 'cost_center' on payment reconciliation ([e9e5ded](e9e5ded36b))
* check type for reference name ([ad648f3](ad648f313c))
* don't set WIP Warehouse if  is checked in WO ([4a17711](4a177113c6))
* Label for applicable dimension table ([cbc8b2d](cbc8b2da0a))
* Pricing rule item group consider UOM ([1ed0b6e](1ed0b6e89b)), closes [#32566](https://github.com/frappe/erpnext/issues/32566)
* query condition change ([88ce59a](88ce59a1ca))
* repayment schedule regeneration ([a19031c](a19031cf9a))
* set `WIP Warehouse` in Job Card ([f09e427](f09e4273d9))
* set stock UOM in args to ensure item price is fetched ([bd2242b](bd2242b285))
* wrong totals in hsn summary report ([79d508f](79d508f4ff))

### Features

* page break in SoA pdf ([e93ac3c](e93ac3c9a8))
2022-11-15 13:02:04 +00:00
Deepesh Garg
1cf5b23d9c Merge pull request #32973 from frappe/version-13-hotfix
chore: release v13
2022-11-15 18:17:49 +05:30
Deepesh Garg
de3453e477 Merge pull request #32934 from rtdany10/hsn-summary-report
fix: wrong hsn summary totals
2022-11-15 16:33:46 +05:30
Deepesh Garg
ee015273c9 Merge pull request #32953 from gavindsouza/rm-dead-validation-pe
chore(payment_entry): Remove dead validations
2022-11-15 13:56:38 +05:30
Deepesh Garg
db3f8d2768 Merge pull request #32961 from frappe/mergify/bp/version-13-hotfix/pr-32956
fix: Label for applicable dimension table (backport #32956)
2022-11-15 13:01:34 +05:30
Gavin D'souza
e1ecc9a819 chore(payment_entry): Remove dead validations 2022-11-15 10:43:47 +05:30
Deepesh Garg
9e340a8307 Merge branch 'version-13-hotfix' into hsn-summary-report 2022-11-15 09:26:00 +05:30
Deepesh Garg
cbc8b2da0a fix: Label for applicable dimension table
(cherry picked from commit 8c13f70fc5)
2022-11-15 03:56:00 +00:00
ruthra kumar
b7ff5fb426 Merge pull request #32930 from ruthra-kumar/ambiguous_cost_center_field
fix: ambiguous 'cost_center' while using payment reconciliation
2022-11-14 16:56:36 +05:30
Sagar Sharma
2b2a4f66ad Merge pull request #32949 from frappe/mergify/bp/version-13-hotfix/pr-32937
refactor: rewrite `job_card.py` queries in QB (backport #32937)
2022-11-14 12:22:59 +05:30
s-aga-r
78ca078474 refactor: rewrite job_card.py queries in QB
(cherry picked from commit 7df2921d38)
2022-11-14 05:57:03 +00:00
Deepesh Garg
5e46567a0b Merge pull request #32940 from deepeshgarg007/psa_pdf_issue_v13
feat: page break in SoA pdf
2022-11-14 10:44:56 +05:30
Deepesh Garg
079cf6899e Merge pull request #32943 from frappe/mergify/bp/version-13-hotfix/pr-32938
chore: Remove raw SQL query (backport #32938)
2022-11-14 10:44:24 +05:30
Sagar Vora
ad648f313c fix: check type for reference name
(cherry picked from commit b06345af46)
2022-11-13 15:11:50 +00:00
Deepesh Garg
9c9c6607f8 chore: Remove qb doc reference
(cherry picked from commit 4b9921782b)
2022-11-13 15:11:49 +00:00
Deepesh Garg
d6901e51ad chore: Remove raw SQL query
(cherry picked from commit 42a59d5c17)
2022-11-13 15:11:48 +00:00
Deepesh Garg
8733ce5ca9 Merge branch 'version-13-hotfix' into psa_pdf_issue_v13 2022-11-13 20:41:38 +05:30
Dany Robert
95f81d3563 chore: remove commented line 2022-11-13 18:53:10 +05:30
Dany Robert
88ce59a1ca fix: query condition change 2022-11-13 18:52:57 +05:30
Dany Robert
e93ac3c9a8 feat: page break in SoA pdf 2022-11-13 18:52:44 +05:30
Sagar Sharma
079fc2dc34 Merge pull request #32936 from frappe/mergify/bp/version-13-hotfix/pr-32913
fix: set stock UOM in args to ensure item price is fetched (backport #32913)
2022-11-12 12:46:54 +05:30
Sagar Vora
bd2242b285 fix: set stock UOM in args to ensure item price is fetched
(cherry picked from commit 57038c3969)
2022-11-12 04:39:52 +00:00
Dany Robert
79d508f4ff fix: wrong totals in hsn summary report 2022-11-12 05:22:31 +01:00
Deepesh Garg
a0cab4c5e7 Merge pull request #32931 from frappe/mergify/bp/version-13-hotfix/pr-32878
fix: repayment schedule regeneration (backport #32878)
2022-11-11 15:15:32 +05:30
Abhinav Raut
a19031cf9a fix: repayment schedule regeneration
(cherry picked from commit d6ab2b3b87)
2022-11-11 08:53:31 +00:00
ruthra kumar
e9e5ded36b fix: ambiguous 'cost_center' on payment reconciliation 2022-11-11 10:14:04 +05:30
Sagar Sharma
fcb6ee22ba Merge pull request #32920 from frappe/mergify/bp/version-13-hotfix/pr-32918
fix: WO Skip Material Transfer to WIP Warehouse (backport #32918)
2022-11-10 18:42:25 +05:30
Sagar Sharma
f09e4273d9 fix: set WIP Warehouse in Job Card
(cherry picked from commit e7fa2e08ad)
2022-11-10 11:43:23 +00:00
Sagar Sharma
4a177113c6 fix: don't set WIP Warehouse if is checked in WO
(cherry picked from commit 9730cd0aec)
2022-11-10 11:43:22 +00:00
Deepesh Garg
972893d00e Merge pull request #32908 from maharshivpatel/item-group-pricing-rule-backport
fix: Pricing rule item group consider UOM
2022-11-10 09:58:50 +05:30
Maharshi Patel
1ed0b6e89b fix: Pricing rule item group consider UOM
Pricing rule's apply_on_field == "item_group" didn't check for UOM. I have added the required checks.

Same as #32566
2022-11-09 17:17:35 +05:30
Deepesh Garg
dafb575500 Merge pull request #32894 from maharshivpatel/add-einvoice-document-date
fix: add Document Date in E-Invoice print format
2022-11-08 21:45:17 +05:30
Maharshi Patel
a16347f325 fix: add Document Date in E-Invoice print format 2022-11-08 16:35:34 +05:30
17 changed files with 270 additions and 110 deletions

View File

@@ -4,7 +4,7 @@ import frappe
from erpnext.hooks import regional_overrides
__version__ = "13.41.1"
__version__ = "13.42.0"
def get_default_company(user=None):

View File

@@ -3,10 +3,6 @@
frappe.ui.form.on('Accounting Dimension Filter', {
refresh: function(frm, cdt, cdn) {
if (frm.doc.accounting_dimension) {
frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value');
}
let help_content =
`<table class="table table-bordered" style="background-color: var(--scrollbar-track-color);">
<tr><td>
@@ -68,6 +64,7 @@ frappe.ui.form.on('Accounting Dimension Filter', {
frm.clear_table("dimensions");
let row = frm.add_child("dimensions");
row.accounting_dimension = frm.doc.accounting_dimension;
frm.fields_dict["dimensions"].grid.update_docfield_property("dimension_value", "label", frm.doc.accounting_dimension);
frm.refresh_field("dimensions");
frm.trigger('setup_filters');
},

View File

@@ -43,20 +43,13 @@ frappe.ui.form.on('Bank Guarantee', {
reference_docname: function(frm) {
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
let fields_to_fetch = ["grand_total"];
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
if (frm.doc.reference_doctype == "Sales Order") {
fields_to_fetch.push("project");
}
fields_to_fetch.push(party_field);
frappe.call({
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_vouchar_detials",
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details",
args: {
"column_list": fields_to_fetch,
"doctype": frm.doc.reference_doctype,
"docname": frm.doc.reference_docname
"bank_guarantee_type": frm.doc.bg_type,
"reference_name": frm.doc.reference_docname
},
callback: function(r) {
if (r.message) {

View File

@@ -2,11 +2,8 @@
# For license information, please see license.txt
import json
import frappe
from frappe import _
from frappe.desk.search import sanitize_searchfield
from frappe.model.document import Document
@@ -25,14 +22,18 @@ class BankGuarantee(Document):
@frappe.whitelist()
def get_vouchar_detials(column_list, doctype, docname):
column_list = json.loads(column_list)
for col in column_list:
sanitize_searchfield(col)
return frappe.db.sql(
""" select {columns} from `tab{doctype}` where name=%s""".format(
columns=", ".join(column_list), doctype=doctype
),
docname,
as_dict=1,
)[0]
def get_voucher_details(bank_guarantee_type: str, reference_name: str):
if not isinstance(reference_name, str):
raise TypeError("reference_name must be a string")
fields_to_fetch = ["grand_total"]
if bank_guarantee_type == "Receiving":
doctype = "Sales Order"
fields_to_fetch.append("customer")
fields_to_fetch.append("project")
else:
doctype = "Purchase Order"
fields_to_fetch.append("supplier")
return frappe.db.get_value(doctype, reference_name, fields_to_fetch, as_dict=True)

View File

@@ -67,7 +67,6 @@ class PaymentEntry(AccountsController):
self.set_missing_values()
self.validate_payment_type()
self.validate_party_details()
self.validate_bank_accounts()
self.set_exchange_rate()
self.validate_mandatory()
self.validate_reference_documents()
@@ -250,23 +249,6 @@ class PaymentEntry(AccountsController):
if not frappe.db.exists(self.party_type, self.party):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
if self.party_account and self.party_type in ("Customer", "Supplier"):
self.validate_account_type(
self.party_account, [erpnext.get_party_account_type(self.party_type)]
)
def validate_bank_accounts(self):
if self.payment_type in ("Pay", "Internal Transfer"):
self.validate_account_type(self.paid_from, ["Bank", "Cash"])
if self.payment_type in ("Receive", "Internal Transfer"):
self.validate_account_type(self.paid_to, ["Bank", "Cash"])
def validate_account_type(self, account, account_types):
account_type = frappe.db.get_value("Account", account, "account_type")
# if account_type not in account_types:
# frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
def set_exchange_rate(self, ref_doc=None):
self.set_source_exchange_rate(ref_doc)
self.set_target_exchange_rate(ref_doc)

View File

@@ -47,6 +47,10 @@ class PaymentReconciliation(Document):
def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
condition = self.get_conditions(get_payments=True)
if self.get("cost_center"):
condition += " and cost_center = '{0}' ".format(self.cost_center)
payment_entries = get_advance_payment_entries(
self.party_type,
self.party,
@@ -61,6 +65,10 @@ class PaymentReconciliation(Document):
def get_jv_entries(self):
condition = self.get_conditions()
if self.get("cost_center"):
condition += " and t2.cost_center = '{0}' ".format(self.cost_center)
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
@@ -113,6 +121,10 @@ class PaymentReconciliation(Document):
def get_dr_or_cr_notes(self):
condition = self.get_conditions(get_return_invoices=True)
if self.get("cost_center"):
condition += " and doc.cost_center = '{0}' ".format(self.cost_center)
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
@@ -172,6 +184,9 @@ class PaymentReconciliation(Document):
condition = self.get_conditions(get_invoices=True)
if self.get("cost_center"):
condition += " and cost_center = '{0}' ".format(self.cost_center)
non_reconciled_invoices = get_outstanding_invoices(
self.party_type, self.party, self.receivable_payable_account, condition=condition
)
@@ -357,9 +372,6 @@ class PaymentReconciliation(Document):
def get_conditions(self, get_invoices=False, get_payments=False, get_return_invoices=False):
condition = " and company = '{0}' ".format(self.company)
if self.get("cost_center"):
condition = " and cost_center = '{0}' ".format(self.cost_center)
if get_invoices:
condition += (
" and posting_date >= {0}".format(frappe.db.escape(self.from_invoice_date))

View File

@@ -712,6 +712,140 @@ class TestPricingRule(unittest.TestCase):
item.delete()
def test_item_group_price_with_blank_uom_pricing_rule(self):
group = frappe.get_doc(
doctype="Item Group",
item_group_name="_Test Pricing Rule Item Group",
parent_item_group="All Item Groups",
)
group.save()
properties = {
"item_code": "Item with Group Blank UOM",
"item_group": "_Test Pricing Rule Item Group",
"stock_uom": "Nos",
"sales_uom": "Box",
"uoms": [dict(uom="Box", conversion_factor=10)],
}
item = make_item(properties=properties)
make_item_price("Item with Group Blank UOM", "_Test Price List", 100)
pricing_rule_record = {
"doctype": "Pricing Rule",
"title": "_Test Item with Group Blank UOM Rule",
"apply_on": "Item Group",
"item_groups": [
{
"item_group": "_Test Pricing Rule Item Group",
}
],
"selling": 1,
"currency": "INR",
"rate_or_discount": "Rate",
"rate": 101,
"company": "_Test Company",
}
rule = frappe.get_doc(pricing_rule_record)
rule.insert()
si = create_sales_invoice(
do_not_save=True, item_code="Item with Group Blank UOM", uom="Box", conversion_factor=10
)
si.selling_price_list = "_Test Price List"
si.save()
# If UOM is blank consider it as stock UOM and apply pricing_rule on all UOM.
# rate is 101, Selling UOM is Box that have conversion_factor of 10 so 101 * 10 = 1010
self.assertEqual(si.items[0].price_list_rate, 1010)
self.assertEqual(si.items[0].rate, 1010)
si.delete()
si = create_sales_invoice(do_not_save=True, item_code="Item with Group Blank UOM", uom="Nos")
si.selling_price_list = "_Test Price List"
si.save()
# UOM is blank so consider it as stock UOM and apply pricing_rule on all UOM.
# rate is 101, Selling UOM is Nos that have conversion_factor of 1 so 101 * 1 = 101
self.assertEqual(si.items[0].price_list_rate, 101)
self.assertEqual(si.items[0].rate, 101)
si.delete()
rule.delete()
frappe.get_doc("Item Price", {"item_code": "Item with Group Blank UOM"}).delete()
item.delete()
group.delete()
def test_item_group_price_with_selling_uom_pricing_rule(self):
group = frappe.get_doc(
doctype="Item Group",
item_group_name="_Test Pricing Rule Item Group UOM",
parent_item_group="All Item Groups",
)
group.save()
properties = {
"item_code": "Item with Group UOM other than Stock",
"item_group": "_Test Pricing Rule Item Group UOM",
"stock_uom": "Nos",
"sales_uom": "Box",
"uoms": [dict(uom="Box", conversion_factor=10)],
}
item = make_item(properties=properties)
make_item_price("Item with Group UOM other than Stock", "_Test Price List", 100)
pricing_rule_record = {
"doctype": "Pricing Rule",
"title": "_Test Item with Group UOM other than Stock Rule",
"apply_on": "Item Group",
"item_groups": [
{
"item_group": "_Test Pricing Rule Item Group UOM",
"uom": "Box",
}
],
"selling": 1,
"currency": "INR",
"rate_or_discount": "Rate",
"rate": 101,
"company": "_Test Company",
}
rule = frappe.get_doc(pricing_rule_record)
rule.insert()
si = create_sales_invoice(
do_not_save=True,
item_code="Item with Group UOM other than Stock",
uom="Box",
conversion_factor=10,
)
si.selling_price_list = "_Test Price List"
si.save()
# UOM is Box so apply pricing_rule only on Box UOM.
# Selling UOM is Box and as both UOM are same no need to multiply by conversion_factor.
self.assertEqual(si.items[0].price_list_rate, 101)
self.assertEqual(si.items[0].rate, 101)
si.delete()
si = create_sales_invoice(
do_not_save=True, item_code="Item with Group UOM other than Stock", uom="Nos"
)
si.selling_price_list = "_Test Price List"
si.save()
# UOM is Box so pricing_rule won't apply as selling_uom is Nos.
# As Pricing Rule is not applied price of 100 will be fetched from Item Price List.
self.assertEqual(si.items[0].price_list_rate, 100)
self.assertEqual(si.items[0].rate, 100)
si.delete()
rule.delete()
frappe.get_doc("Item Price", {"item_code": "Item with Group UOM other than Stock"}).delete()
item.delete()
group.delete()
def test_pricing_rule_for_different_currency(self):
make_item("Test Sanitizer Item")

View File

@@ -127,7 +127,12 @@ def _get_pricing_rules(apply_on, args, values):
values["variant_of"] = args.variant_of
elif apply_on_field == "item_group":
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
if args.get("uom", None):
item_conditions += (
" and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
child_doc=child_doc, item_uom=args.get("uom")
)
)
conditions += get_other_conditions(conditions, values, args)
warehouse_conditions = _get_tree_conditions(args, "Warehouse", "`tabPricing Rule`")
if warehouse_conditions:

View File

@@ -8,7 +8,8 @@ frappe.ui.form.on('Process Statement Of Accounts', {
},
refresh: function(frm){
if(!frm.doc.__islocal) {
frm.add_custom_button('Send Emails',function(){
frm.add_custom_button(__('Send Emails'), function(){
if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
frappe.call({
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails",
args: {
@@ -24,8 +25,9 @@ frappe.ui.form.on('Process Statement Of Accounts', {
}
});
});
frm.add_custom_button('Download',function(){
var url = frappe.urllib.get_full_url(
frm.add_custom_button(__('Download'), function(){
if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
let url = frappe.urllib.get_full_url(
'/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?'
+ 'document_name='+encodeURIComponent(frm.doc.name))
$.ajax({

View File

@@ -27,6 +27,7 @@
"customers",
"preferences",
"orientation",
"include_break",
"include_ageing",
"ageing_based_on",
"section_break_14",
@@ -284,10 +285,16 @@
"fieldtype": "Link",
"label": "Terms and Conditions",
"options": "Terms and Conditions"
},
{
"default": "1",
"fieldname": "include_break",
"fieldtype": "Check",
"label": "Page Break After Each SoA"
}
],
"links": [],
"modified": "2021-09-06 21:00:45.732505",
"modified": "2022-10-17 17:47:08.662475",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
@@ -320,5 +327,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@@ -6,6 +6,7 @@ import copy
import frappe
from frappe import _
from frappe.desk.reportview import get_match_cond
from frappe.model.document import Document
from frappe.utils import add_days, add_months, format_date, getdate, today
from frappe.utils.jinja import validate_template
@@ -128,7 +129,8 @@ def get_report_pdf(doc, consolidated=True):
if not bool(statement_dict):
return False
elif consolidated:
result = "".join(list(statement_dict.values()))
delimiter = '<div style="page-break-before: always;"></div>' if doc.include_break else ""
result = delimiter.join(list(statement_dict.values()))
return get_pdf(result, {"orientation": doc.orientation})
else:
for customer, statement_html in statement_dict.items():
@@ -240,8 +242,6 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
if int(primary_mandatory):
if primary_email == "":
continue
elif (billing_email == "") and (primary_email == ""):
continue
customer_list.append(
{"name": customer.name, "primary_email": primary_email, "billing_email": billing_email}
@@ -273,8 +273,12 @@ def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=Tr
link.link_doctype='Customer'
and link.link_name=%s
and contact.is_billing_contact=1
{mcond}
ORDER BY
contact.creation desc""",
contact.creation desc
""".format(
mcond=get_match_cond("Contact")
),
customer_name,
)
@@ -313,6 +317,8 @@ def send_emails(document_name, from_scheduler=False):
attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}]
recipients, cc = get_recipients_and_cc(customer, doc)
if not recipients:
continue
context = get_context(customer, doc)
subject = frappe.render_template(doc.subject, context)
message = frappe.render_template(doc.body, context)

View File

@@ -50,6 +50,10 @@
<div class="col-xs-4"><label>Document No</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.No }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Document Date</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.Dt }}</div>
</div>
</div>
<div class="col-xs-4 column-break">
<img src="{{ doc.qrcode_image }}" width="175px" style="float: right;">

View File

@@ -577,8 +577,8 @@ def regenerate_repayment_schedule(loan, cancel=0):
loan_doc = frappe.get_doc("Loan", loan)
next_accrual_date = None
accrued_entries = 0
last_repayment_amount = 0
last_balance_amount = 0
last_repayment_amount = None
last_balance_amount = None
for term in reversed(loan_doc.get("repayment_schedule")):
if not term.is_accrued:
@@ -586,9 +586,9 @@ def regenerate_repayment_schedule(loan, cancel=0):
loan_doc.remove(term)
else:
accrued_entries += 1
if not last_repayment_amount:
if last_repayment_amount is None:
last_repayment_amount = term.total_payment
if not last_balance_amount:
if last_balance_amount is None:
last_balance_amount = term.balance_loan_amount
loan_doc.save()

View File

@@ -7,6 +7,8 @@ import frappe
from frappe import _, bold
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Criterion
from frappe.query_builder.functions import IfNull, Max, Min
from frappe.utils import (
add_days,
add_to_date,
@@ -54,6 +56,9 @@ class JobCard(Document):
self.set_onload("job_card_excess_transfer", excess_transfer)
self.set_onload("work_order_stopped", self.is_work_order_stopped())
def before_validate(self):
self.set_wip_warehouse()
def validate(self):
self.validate_time_logs()
self.set_status()
@@ -109,43 +114,44 @@ class JobCard(Document):
def get_overlap_for(self, args, check_next_available_slot=False):
production_capacity = 1
jc = frappe.qb.DocType("Job Card")
jctl = frappe.qb.DocType("Job Card Time Log")
time_conditions = [
((jctl.from_time < args.from_time) & (jctl.to_time > args.from_time)),
((jctl.from_time < args.to_time) & (jctl.to_time > args.to_time)),
((jctl.from_time >= args.from_time) & (jctl.to_time <= args.to_time)),
]
if check_next_available_slot:
time_conditions.append(((jctl.from_time >= args.from_time) & (jctl.to_time >= args.to_time)))
query = (
frappe.qb.from_(jctl)
.from_(jc)
.select(jc.name.as_("name"), jctl.to_time)
.where(
(jctl.parent == jc.name)
& (Criterion.any(time_conditions))
& (jctl.name != f"{args.name or 'No Name'}")
& (jc.name != f"{args.parent or 'No Name'}")
& (jc.docstatus < 2)
)
.orderby(jctl.to_time, order=frappe.qb.desc)
)
if self.workstation:
production_capacity = (
frappe.get_cached_value("Workstation", self.workstation, "production_capacity") or 1
)
validate_overlap_for = " and jc.workstation = %(workstation)s "
query = query.where(jc.workstation == self.workstation)
if args.get("employee"):
# override capacity for employee
production_capacity = 1
validate_overlap_for = " and jctl.employee = %(employee)s "
query = query.where(jctl.employee == args.get("employee"))
extra_cond = ""
if check_next_available_slot:
extra_cond = " or (%(from_time)s <= jctl.from_time and %(to_time)s <= jctl.to_time)"
existing = frappe.db.sql(
"""select jc.name as name, jctl.to_time from
`tabJob Card Time Log` jctl, `tabJob Card` jc where jctl.parent = jc.name and
(
(%(from_time)s > jctl.from_time and %(from_time)s < jctl.to_time) or
(%(to_time)s > jctl.from_time and %(to_time)s < jctl.to_time) or
(%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time) {0}
)
and jctl.name != %(name)s and jc.name != %(parent)s and jc.docstatus < 2 {1}
order by jctl.to_time desc""".format(
extra_cond, validate_overlap_for
),
{
"from_time": args.from_time,
"to_time": args.to_time,
"name": args.name or "No Name",
"parent": args.parent or "No Name",
"employee": args.get("employee"),
"workstation": self.workstation,
},
as_dict=True,
)
existing = query.run(as_dict=True)
if existing and production_capacity > len(existing):
return
@@ -485,18 +491,21 @@ class JobCard(Document):
)
def update_work_order_data(self, for_quantity, time_in_mins, wo):
time_data = frappe.db.sql(
"""
SELECT
min(from_time) as start_time, max(to_time) as end_time
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
WHERE
jctl.parent = jc.name and jc.work_order = %s and jc.operation_id = %s
and jc.docstatus = 1 and IFNULL(jc.is_corrective_job_card, 0) = 0
""",
(self.work_order, self.operation_id),
as_dict=1,
)
jc = frappe.qb.DocType("Job Card")
jctl = frappe.qb.DocType("Job Card Time Log")
time_data = (
frappe.qb.from_(jc)
.from_(jctl)
.select(Min(jctl.from_time).as_("start_time"), Max(jctl.to_time).as_("end_time"))
.where(
(jctl.parent == jc.name)
& (jc.work_order == self.work_order)
& (jc.operation_id == self.operation_id)
& (jc.docstatus == 1)
& (IfNull(jc.is_corrective_job_card, 0) == 0)
)
).run(as_dict=True)
for data in wo.operations:
if data.get("name") == self.operation_id:
@@ -639,6 +648,12 @@ class JobCard(Document):
if update_status:
self.db_set("status", self.status)
def set_wip_warehouse(self):
if not self.wip_warehouse:
self.wip_warehouse = frappe.db.get_single_value(
"Manufacturing Settings", "default_wip_warehouse"
)
def validate_operation_id(self):
if (
self.get("operation_id")

View File

@@ -145,7 +145,7 @@ class WorkOrder(Document):
frappe.throw(_("Sales Order {0} is {1}").format(self.sales_order, status))
def set_default_warehouse(self):
if not self.wip_warehouse:
if not self.wip_warehouse and not self.skip_transfer:
self.wip_warehouse = frappe.db.get_single_value(
"Manufacturing Settings", "default_wip_warehouse"
)

View File

@@ -35,7 +35,7 @@ def _execute(filters=None):
data = []
added_item = []
for d in item_list:
if (d.parent, d.item_code) not in added_item:
if (d.parent, d.gst_hsn_code, d.item_code) not in added_item:
row = [d.gst_hsn_code, d.description, d.stock_uom, d.stock_qty]
total_tax = 0
tax_rate = 0
@@ -52,7 +52,7 @@ def _execute(filters=None):
item_tax = itemised_tax.get((d.parent, d.item_code), {}).get(tax, {})
row += [item_tax.get("tax_amount", 0)]
data.append(row)
added_item.append((d.parent, d.item_code))
added_item.append((d.parent, d.gst_hsn_code, d.item_code))
if data:
data = get_merged_data(columns, data) # merge same hsn code data
return columns, data
@@ -161,11 +161,9 @@ def get_items(filters):
GROUP BY
`tabSales Invoice Item`.parent,
`tabSales Invoice Item`.item_code,
`tabSales Invoice Item`.gst_hsn_code,
`tabSales Invoice Item`.uom
`tabSales Invoice Item`.gst_hsn_code
ORDER BY
`tabSales Invoice Item`.gst_hsn_code,
`tabSales Invoice Item`.uom
`tabSales Invoice Item`.gst_hsn_code
""".format(
conditions=conditions
),

View File

@@ -315,6 +315,9 @@ def get_basic_details(args, item, overwrite_warehouse=True):
else:
args.uom = item.stock_uom
# Set stock UOM in args, so that it can be used while fetching item price
args.stock_uom = item.stock_uom
if args.get("batch_no") and item.name != frappe.get_cached_value(
"Batch", args.get("batch_no"), "item"
):