Merge branch 'develop' into field-filters-e-com
This commit is contained in:
commit
87f1617780
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@ -12,6 +12,7 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
- name: Setup Node.js v14
|
- name: Setup Node.js v14
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
@ -21,5 +22,10 @@ jobs:
|
|||||||
npm install @semantic-release/git @semantic-release/exec --no-save
|
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
GIT_AUTHOR_NAME: "Frappe PR Bot"
|
||||||
|
GIT_AUTHOR_EMAIL: "developers@frappe.io"
|
||||||
|
GIT_COMMITTER_NAME: "Frappe PR Bot"
|
||||||
|
GIT_COMMITTER_EMAIL: "developers@frappe.io"
|
||||||
run: npx semantic-release
|
run: npx semantic-release
|
@ -153,6 +153,31 @@ class TestEmployeeCheckin(FrappeTestCase):
|
|||||||
log = make_checkin(employee, timestamp)
|
log = make_checkin(employee, timestamp)
|
||||||
self.assertIsNone(log.shift)
|
self.assertIsNone(log.shift)
|
||||||
|
|
||||||
|
def test_fetch_shift_for_assignment_with_end_date(self):
|
||||||
|
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
|
||||||
|
|
||||||
|
# shift setup for 8-12
|
||||||
|
shift1 = setup_shift_type()
|
||||||
|
# 12:30 - 16:30
|
||||||
|
shift2 = setup_shift_type(shift_type="Shift 2", start_time="12:30:00", end_time="16:30:00")
|
||||||
|
|
||||||
|
date = getdate()
|
||||||
|
make_shift_assignment(shift1.name, employee, date, add_days(date, 15))
|
||||||
|
make_shift_assignment(shift2.name, employee, date, add_days(date, 15))
|
||||||
|
|
||||||
|
timestamp = datetime.combine(date, get_time("08:45:00"))
|
||||||
|
log = make_checkin(employee, timestamp)
|
||||||
|
self.assertEqual(log.shift, shift1.name)
|
||||||
|
|
||||||
|
timestamp = datetime.combine(date, get_time("12:45:00"))
|
||||||
|
log = make_checkin(employee, timestamp)
|
||||||
|
self.assertEqual(log.shift, shift2.name)
|
||||||
|
|
||||||
|
# log after end date
|
||||||
|
timestamp = datetime.combine(add_days(date, 16), get_time("12:45:00"))
|
||||||
|
log = make_checkin(employee, timestamp)
|
||||||
|
self.assertIsNone(log.shift)
|
||||||
|
|
||||||
def test_shift_start_and_end_timings(self):
|
def test_shift_start_and_end_timings(self):
|
||||||
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
|
employee = make_employee("test_employee_checkin@example.com", company="_Test Company")
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ def has_overlapping_timings(shift_1: str, shift_2: str) -> bool:
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_events(start, end, filters=None):
|
def get_events(start, end, filters=None):
|
||||||
events = []
|
from frappe.desk.calendar import get_event_conditions
|
||||||
|
|
||||||
employee = frappe.db.get_value(
|
employee = frappe.db.get_value(
|
||||||
"Employee", {"user_id": frappe.session.user}, ["name", "company"], as_dict=True
|
"Employee", {"user_id": frappe.session.user}, ["name", "company"], as_dict=True
|
||||||
@ -132,20 +132,22 @@ def get_events(start, end, filters=None):
|
|||||||
employee = ""
|
employee = ""
|
||||||
company = frappe.db.get_value("Global Defaults", None, "default_company")
|
company = frappe.db.get_value("Global Defaults", None, "default_company")
|
||||||
|
|
||||||
from frappe.desk.reportview import get_filters_cond
|
conditions = get_event_conditions("Shift Assignment", filters)
|
||||||
|
events = add_assignments(start, end, conditions=conditions)
|
||||||
conditions = get_filters_cond("Shift Assignment", filters, [])
|
|
||||||
add_assignments(events, start, end, conditions=conditions)
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
|
||||||
def add_assignments(events, start, end, conditions=None):
|
def add_assignments(start, end, conditions=None):
|
||||||
|
events = []
|
||||||
|
|
||||||
query = """select name, start_date, end_date, employee_name,
|
query = """select name, start_date, end_date, employee_name,
|
||||||
employee, docstatus, shift_type
|
employee, docstatus, shift_type
|
||||||
from `tabShift Assignment` where
|
from `tabShift Assignment` where
|
||||||
|
(
|
||||||
start_date >= %(start_date)s
|
start_date >= %(start_date)s
|
||||||
or end_date <= %(end_date)s
|
or end_date <= %(end_date)s
|
||||||
or (%(start_date)s between start_date and end_date and %(end_date)s between start_date and end_date)
|
or (%(start_date)s between start_date and end_date and %(end_date)s between start_date and end_date)
|
||||||
|
)
|
||||||
and docstatus = 1"""
|
and docstatus = 1"""
|
||||||
if conditions:
|
if conditions:
|
||||||
query += conditions
|
query += conditions
|
||||||
@ -251,7 +253,7 @@ def get_shifts_for_date(employee: str, for_timestamp: datetime) -> List[Dict[str
|
|||||||
Criterion.any(
|
Criterion.any(
|
||||||
[
|
[
|
||||||
assignment.end_date.isnull(),
|
assignment.end_date.isnull(),
|
||||||
(assignment.end_date.isnotnull() & (getdate(for_timestamp.date()) >= assignment.end_date)),
|
(assignment.end_date.isnotnull() & (getdate(for_timestamp.date()) <= assignment.end_date)),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -8,7 +8,7 @@ from frappe.tests.utils import FrappeTestCase
|
|||||||
from frappe.utils import add_days, getdate, nowdate
|
from frappe.utils import add_days, getdate, nowdate
|
||||||
|
|
||||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
from erpnext.hr.doctype.shift_assignment.shift_assignment import OverlappingShiftError
|
from erpnext.hr.doctype.shift_assignment.shift_assignment import OverlappingShiftError, get_events
|
||||||
from erpnext.hr.doctype.shift_type.test_shift_type import make_shift_assignment, setup_shift_type
|
from erpnext.hr.doctype.shift_type.test_shift_type import make_shift_assignment, setup_shift_type
|
||||||
|
|
||||||
test_dependencies = ["Shift Type"]
|
test_dependencies = ["Shift Type"]
|
||||||
@ -154,3 +154,18 @@ class TestShiftAssignment(FrappeTestCase):
|
|||||||
shift_type = setup_shift_type(shift_type="Shift 2", start_time="13:00:00", end_time="15:00:00")
|
shift_type = setup_shift_type(shift_type="Shift 2", start_time="13:00:00", end_time="15:00:00")
|
||||||
date = getdate()
|
date = getdate()
|
||||||
make_shift_assignment(shift_type.name, employee, date)
|
make_shift_assignment(shift_type.name, employee, date)
|
||||||
|
|
||||||
|
def test_shift_assignment_calendar(self):
|
||||||
|
employee1 = make_employee("test_shift_assignment1@example.com", company="_Test Company")
|
||||||
|
employee2 = make_employee("test_shift_assignment2@example.com", company="_Test Company")
|
||||||
|
|
||||||
|
shift_type = setup_shift_type(shift_type="Shift 1", start_time="08:00:00", end_time="12:00:00")
|
||||||
|
date = getdate()
|
||||||
|
shift1 = make_shift_assignment(shift_type.name, employee1, date)
|
||||||
|
make_shift_assignment(shift_type.name, employee2, date)
|
||||||
|
|
||||||
|
events = get_events(
|
||||||
|
start=date, end=date, filters=[["Shift Assignment", "employee", "=", employee1, False]]
|
||||||
|
)
|
||||||
|
self.assertEqual(len(events), 1)
|
||||||
|
self.assertEqual(events[0]["name"], shift1.name)
|
||||||
|
@ -73,10 +73,22 @@ frappe.ui.form.on('Job Card', {
|
|||||||
if (frm.doc.docstatus == 0 && !frm.is_new() &&
|
if (frm.doc.docstatus == 0 && !frm.is_new() &&
|
||||||
(frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
|
(frm.doc.for_quantity > frm.doc.total_completed_qty || !frm.doc.for_quantity)
|
||||||
&& (frm.doc.items || !frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
|
&& (frm.doc.items || !frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
|
||||||
|
|
||||||
|
// if Job Card is link to Work Order, the job card must not be able to start if Work Order not "Started"
|
||||||
|
// and if stock mvt for WIP is required
|
||||||
|
if (frm.doc.work_order) {
|
||||||
|
frappe.db.get_value('Work Order', frm.doc.work_order, ['skip_transfer', 'status'], (result) => {
|
||||||
|
if (result.skip_transfer === 1 || result.status == 'In Process') {
|
||||||
frm.trigger("prepare_timer_buttons");
|
frm.trigger("prepare_timer_buttons");
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
frm.trigger("prepare_timer_buttons");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
frm.trigger("setup_quality_inspection");
|
frm.trigger("setup_quality_inspection");
|
||||||
|
|
||||||
if (frm.doc.work_order) {
|
if (frm.doc.work_order) {
|
||||||
frappe.db.get_value('Work Order', frm.doc.work_order,
|
frappe.db.get_value('Work Order', frm.doc.work_order,
|
||||||
'transfer_material_against').then((r) => {
|
'transfer_material_against').then((r) => {
|
||||||
|
@ -10,17 +10,22 @@ def execute():
|
|||||||
|
|
||||||
frappe.reload_doc("hr", "doctype", "Leave Encashment")
|
frappe.reload_doc("hr", "doctype", "Leave Encashment")
|
||||||
|
|
||||||
additional_salaries = frappe.get_all(
|
if frappe.db.has_column("Leave Encashment", "additional_salary"):
|
||||||
"Additional Salary",
|
|
||||||
fields=["name", "salary_slip", "type", "salary_component"],
|
|
||||||
filters={"salary_slip": ["!=", ""]},
|
|
||||||
group_by="salary_slip",
|
|
||||||
)
|
|
||||||
leave_encashments = frappe.get_all(
|
leave_encashments = frappe.get_all(
|
||||||
"Leave Encashment",
|
"Leave Encashment",
|
||||||
fields=["name", "additional_salary"],
|
fields=["name", "additional_salary"],
|
||||||
filters={"additional_salary": ["!=", ""]},
|
filters={"additional_salary": ["!=", ""]},
|
||||||
)
|
)
|
||||||
|
for leave_encashment in leave_encashments:
|
||||||
|
frappe.db.sql(
|
||||||
|
""" UPDATE `tabAdditional Salary`
|
||||||
|
SET ref_doctype = 'Leave Encashment', ref_docname = %s
|
||||||
|
WHERE name = %s
|
||||||
|
""",
|
||||||
|
(leave_encashment["name"], leave_encashment["additional_salary"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
if frappe.db.has_column("Employee Incentive", "additional_salary"):
|
||||||
employee_incentives = frappe.get_all(
|
employee_incentives = frappe.get_all(
|
||||||
"Employee Incentive",
|
"Employee Incentive",
|
||||||
fields=["name", "additional_salary"],
|
fields=["name", "additional_salary"],
|
||||||
@ -36,13 +41,12 @@ def execute():
|
|||||||
(incentive["name"], incentive["additional_salary"]),
|
(incentive["name"], incentive["additional_salary"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
for leave_encashment in leave_encashments:
|
if frappe.db.has_column("Additional Salary", "salary_slip"):
|
||||||
frappe.db.sql(
|
additional_salaries = frappe.get_all(
|
||||||
""" UPDATE `tabAdditional Salary`
|
"Additional Salary",
|
||||||
SET ref_doctype = 'Leave Encashment', ref_docname = %s
|
fields=["name", "salary_slip", "type", "salary_component"],
|
||||||
WHERE name = %s
|
filters={"salary_slip": ["!=", ""]},
|
||||||
""",
|
group_by="salary_slip",
|
||||||
(leave_encashment["name"], leave_encashment["additional_salary"]),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
salary_slips = [sal["salary_slip"] for sal in additional_salaries]
|
salary_slips = [sal["salary_slip"] for sal in additional_salaries]
|
||||||
|
@ -1074,7 +1074,7 @@ class GSPConnector:
|
|||||||
"Distance": cint(eway_bill_details.distance),
|
"Distance": cint(eway_bill_details.distance),
|
||||||
"TransMode": eway_bill_details.mode_of_transport,
|
"TransMode": eway_bill_details.mode_of_transport,
|
||||||
"TransId": eway_bill_details.gstin,
|
"TransId": eway_bill_details.gstin,
|
||||||
"TransName": eway_bill_details.transporter,
|
"TransName": eway_bill_details.name,
|
||||||
"TrnDocDt": eway_bill_details.document_date,
|
"TrnDocDt": eway_bill_details.document_date,
|
||||||
"TrnDocNo": eway_bill_details.document_name,
|
"TrnDocNo": eway_bill_details.document_name,
|
||||||
"VehNo": eway_bill_details.vehicle_no,
|
"VehNo": eway_bill_details.vehicle_no,
|
||||||
|
@ -81,7 +81,7 @@ def get_data(conditions, filters):
|
|||||||
ON sii.so_detail = soi.name and sii.docstatus = 1)
|
ON sii.so_detail = soi.name and sii.docstatus = 1)
|
||||||
LEFT JOIN `tabDelivery Note Item` dni
|
LEFT JOIN `tabDelivery Note Item` dni
|
||||||
on dni.so_detail = soi.name
|
on dni.so_detail = soi.name
|
||||||
RIGHT JOIN `tabDelivery Note` dn
|
LEFT JOIN `tabDelivery Note` dn
|
||||||
on dni.parent = dn.name and dn.docstatus = 1
|
on dni.parent = dn.name and dn.docstatus = 1
|
||||||
WHERE
|
WHERE
|
||||||
soi.parent = so.name
|
soi.parent = so.name
|
||||||
|
@ -0,0 +1,166 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
from frappe.utils import add_days
|
||||||
|
|
||||||
|
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
|
||||||
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
|
from erpnext.selling.report.sales_order_analysis.sales_order_analysis import execute
|
||||||
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
|
|
||||||
|
test_dependencies = ["Sales Order", "Item", "Sales Invoice", "Delivery Note"]
|
||||||
|
|
||||||
|
|
||||||
|
class TestSalesOrderAnalysis(FrappeTestCase):
|
||||||
|
def create_sales_order(self, transaction_date):
|
||||||
|
item = create_item(item_code="_Test Excavator", is_stock_item=0)
|
||||||
|
so = make_sales_order(
|
||||||
|
transaction_date=transaction_date,
|
||||||
|
item=item.item_code,
|
||||||
|
qty=10,
|
||||||
|
rate=100000,
|
||||||
|
do_not_save=True,
|
||||||
|
)
|
||||||
|
so.po_no = ""
|
||||||
|
so.taxes_and_charges = ""
|
||||||
|
so.taxes = ""
|
||||||
|
so.items[0].delivery_date = add_days(transaction_date, 15)
|
||||||
|
so.save()
|
||||||
|
so.submit()
|
||||||
|
return item, so
|
||||||
|
|
||||||
|
def create_sales_invoice(self, so):
|
||||||
|
sinv = make_sales_invoice(so.name)
|
||||||
|
sinv.posting_date = so.transaction_date
|
||||||
|
sinv.taxes_and_charges = ""
|
||||||
|
sinv.taxes = ""
|
||||||
|
sinv.insert()
|
||||||
|
sinv.submit()
|
||||||
|
return sinv
|
||||||
|
|
||||||
|
def create_delivery_note(self, so):
|
||||||
|
dn = make_delivery_note(so.name)
|
||||||
|
dn.set_posting_time = True
|
||||||
|
dn.posting_date = add_days(so.transaction_date, 1)
|
||||||
|
dn.save()
|
||||||
|
dn.submit()
|
||||||
|
return dn
|
||||||
|
|
||||||
|
def test_01_so_to_deliver_and_bill(self):
|
||||||
|
transaction_date = "2021-06-01"
|
||||||
|
item, so = self.create_sales_order(transaction_date)
|
||||||
|
columns, data, message, chart = execute(
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"from_date": "2021-06-01",
|
||||||
|
"to_date": "2021-06-30",
|
||||||
|
"status": ["To Deliver and Bill"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expected_value = {
|
||||||
|
"status": "To Deliver and Bill",
|
||||||
|
"sales_order": so.name,
|
||||||
|
"delay_days": frappe.utils.date_diff(frappe.utils.datetime.date.today(), so.delivery_date),
|
||||||
|
"qty": 10,
|
||||||
|
"delivered_qty": 0,
|
||||||
|
"pending_qty": 10,
|
||||||
|
"qty_to_bill": 10,
|
||||||
|
"time_taken_to_deliver": 0,
|
||||||
|
}
|
||||||
|
self.assertEqual(len(data), 1)
|
||||||
|
for key, val in expected_value.items():
|
||||||
|
with self.subTest(key=key, val=val):
|
||||||
|
self.assertEqual(data[0][key], val)
|
||||||
|
|
||||||
|
def test_02_so_to_deliver(self):
|
||||||
|
transaction_date = "2021-06-01"
|
||||||
|
item, so = self.create_sales_order(transaction_date)
|
||||||
|
self.create_sales_invoice(so)
|
||||||
|
columns, data, message, chart = execute(
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"from_date": "2021-06-01",
|
||||||
|
"to_date": "2021-06-30",
|
||||||
|
"status": ["To Deliver"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expected_value = {
|
||||||
|
"status": "To Deliver",
|
||||||
|
"sales_order": so.name,
|
||||||
|
"delay_days": frappe.utils.date_diff(frappe.utils.datetime.date.today(), so.delivery_date),
|
||||||
|
"qty": 10,
|
||||||
|
"delivered_qty": 0,
|
||||||
|
"pending_qty": 10,
|
||||||
|
"qty_to_bill": 0,
|
||||||
|
"time_taken_to_deliver": 0,
|
||||||
|
}
|
||||||
|
self.assertEqual(len(data), 1)
|
||||||
|
for key, val in expected_value.items():
|
||||||
|
with self.subTest(key=key, val=val):
|
||||||
|
self.assertEqual(data[0][key], val)
|
||||||
|
|
||||||
|
def test_03_so_to_bill(self):
|
||||||
|
transaction_date = "2021-06-01"
|
||||||
|
item, so = self.create_sales_order(transaction_date)
|
||||||
|
self.create_delivery_note(so)
|
||||||
|
columns, data, message, chart = execute(
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"from_date": "2021-06-01",
|
||||||
|
"to_date": "2021-06-30",
|
||||||
|
"status": ["To Bill"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expected_value = {
|
||||||
|
"status": "To Bill",
|
||||||
|
"sales_order": so.name,
|
||||||
|
"delay_days": frappe.utils.date_diff(frappe.utils.datetime.date.today(), so.delivery_date),
|
||||||
|
"qty": 10,
|
||||||
|
"delivered_qty": 10,
|
||||||
|
"pending_qty": 0,
|
||||||
|
"qty_to_bill": 10,
|
||||||
|
"time_taken_to_deliver": 86400,
|
||||||
|
}
|
||||||
|
self.assertEqual(len(data), 1)
|
||||||
|
for key, val in expected_value.items():
|
||||||
|
with self.subTest(key=key, val=val):
|
||||||
|
self.assertEqual(data[0][key], val)
|
||||||
|
|
||||||
|
def test_04_so_completed(self):
|
||||||
|
transaction_date = "2021-06-01"
|
||||||
|
item, so = self.create_sales_order(transaction_date)
|
||||||
|
self.create_sales_invoice(so)
|
||||||
|
self.create_delivery_note(so)
|
||||||
|
columns, data, message, chart = execute(
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"from_date": "2021-06-01",
|
||||||
|
"to_date": "2021-06-30",
|
||||||
|
"status": ["Completed"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
expected_value = {
|
||||||
|
"status": "Completed",
|
||||||
|
"sales_order": so.name,
|
||||||
|
"delay_days": frappe.utils.date_diff(frappe.utils.datetime.date.today(), so.delivery_date),
|
||||||
|
"qty": 10,
|
||||||
|
"delivered_qty": 10,
|
||||||
|
"pending_qty": 0,
|
||||||
|
"qty_to_bill": 0,
|
||||||
|
"billed_qty": 10,
|
||||||
|
"time_taken_to_deliver": 86400,
|
||||||
|
}
|
||||||
|
self.assertEqual(len(data), 1)
|
||||||
|
for key, val in expected_value.items():
|
||||||
|
with self.subTest(key=key, val=val):
|
||||||
|
self.assertEqual(data[0][key], val)
|
||||||
|
|
||||||
|
def test_05_all_so_status(self):
|
||||||
|
columns, data, message, chart = execute(
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"from_date": "2021-06-01",
|
||||||
|
"to_date": "2021-06-30",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# SO's from first 4 test cases should be in output
|
||||||
|
self.assertEqual(len(data), 4)
|
Loading…
x
Reference in New Issue
Block a user