Rename Time Sheet doctype
This commit is contained in:
parent
21f443e37c
commit
e94d18b4cd
@ -238,7 +238,7 @@ class SalesInvoice(SellingController):
|
||||
def update_time_sheet(self, sales_invoice):
|
||||
for d in self.timesheets:
|
||||
if d.time_sheet:
|
||||
timesheet = frappe.get_doc("Time Sheet", d.time_sheet)
|
||||
timesheet = frappe.get_doc("Timesheet", d.time_sheet)
|
||||
timesheet.sales_invoice = sales_invoice
|
||||
timesheet.flags.ignore_validate_update_after_submit = True
|
||||
timesheet.set_status()
|
||||
@ -247,9 +247,9 @@ class SalesInvoice(SellingController):
|
||||
def validate_time_sheets_are_submitted(self):
|
||||
for data in self.timesheets:
|
||||
if data.time_sheet:
|
||||
status = frappe.db.get_value("Time Sheet", data.time_sheet, "status")
|
||||
status = frappe.db.get_value("Timesheet", data.time_sheet, "status")
|
||||
if status not in ['Submitted', 'Payslip']:
|
||||
frappe.throw(_("Time Sheet {0} is already completed or cancelled").format(data.time_sheet))
|
||||
frappe.throw(_("Timesheet {0} is already completed or cancelled").format(data.time_sheet))
|
||||
|
||||
def set_pos_fields(self, for_validate=False):
|
||||
"""Set retail related fields from POS Profiles"""
|
||||
|
@ -23,7 +23,7 @@
|
||||
"label": "Time Sheet",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Time Sheet",
|
||||
"options": "Timesheet",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -71,7 +71,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-06-15 23:56:06.131202",
|
||||
"modified": "2016-07-06 18:35:46.072695",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Timesheet",
|
||||
|
@ -31,13 +31,13 @@ def get_data():
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Time Sheet",
|
||||
"description": _("Time Sheet for tasks."),
|
||||
"name": "Timesheet",
|
||||
"description": _("Timesheet for tasks."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Activity Type",
|
||||
"description": _("Types of activities for Time Sheets"),
|
||||
"description": _("Types of activities for Time Logs"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
@ -53,8 +53,8 @@ def get_data():
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Daily Time Sheet Summary",
|
||||
"doctype": "Time Sheet"
|
||||
"name": "Daily Timesheet Summary",
|
||||
"doctype": "Timesheet"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
|
@ -9,7 +9,7 @@ links = {
|
||||
},
|
||||
{
|
||||
'label': _('Payroll'),
|
||||
'items': ['Salary Structure', 'Salary Slip', 'Time Sheet']
|
||||
'items': ['Salary Structure', 'Salary Slip', 'Timesheet']
|
||||
},
|
||||
{
|
||||
'label': _('Expense'),
|
||||
|
@ -64,7 +64,7 @@ class SalarySlip(TransactionBase):
|
||||
if self.salary_slip_based_on_timesheet and not self.get('timesheets'):
|
||||
self.set("timesheets", [])
|
||||
|
||||
timesheets = frappe.db.sql(""" select * from `tabTime Sheet` where employee = %(employee)s and (status = 'Submitted' or
|
||||
timesheets = frappe.db.sql(""" select * from `tabTimesheet` where employee = %(employee)s and (status = 'Submitted' or
|
||||
status = 'Billed')""", {'employee': self.employee}, as_dict=1)
|
||||
|
||||
for data in timesheets:
|
||||
@ -220,16 +220,16 @@ class SalarySlip(TransactionBase):
|
||||
frappe.throw(_("Salary Slip of employee {0} already created for this period").format(self.employee))
|
||||
else:
|
||||
for data in self.timesheets:
|
||||
if frappe.db.get_value('Time Sheet', data.time_sheet, 'status') == 'Payrolled':
|
||||
if frappe.db.get_value('Timesheet', data.time_sheet, 'status') == 'Payrolled':
|
||||
frappe.throw(_("Salary Slip of employee {0} already created for time sheet {1}").format(self.employee, data.time_sheet))
|
||||
|
||||
def calculate_earning_total(self):
|
||||
self.gross_pay = flt(self.arrear_amount) + flt(self.leave_encashment_amount)
|
||||
for d in self.get("earnings"):
|
||||
if cint(d.depends_on_lwp) == 1:
|
||||
if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet:
|
||||
d.amount = rounded((flt(d.default_amount) * flt(self.payment_days)
|
||||
/ cint(self.total_days_in_month)), self.precision("amount", "earnings"))
|
||||
elif not self.payment_days:
|
||||
elif not self.payment_days and not self.salary_slip_based_on_timesheet:
|
||||
d.amount = 0
|
||||
elif not d.amount:
|
||||
d.amount = d.default_amount
|
||||
@ -238,10 +238,10 @@ class SalarySlip(TransactionBase):
|
||||
def calculate_ded_total(self):
|
||||
self.total_deduction = 0
|
||||
for d in self.get('deductions'):
|
||||
if cint(d.depends_on_lwp) == 1:
|
||||
if cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet:
|
||||
d.amount = rounded((flt(d.amount) * flt(self.payment_days)
|
||||
/ cint(self.total_days_in_month)), self.precision("amount", "deductions"))
|
||||
elif not self.payment_days:
|
||||
elif not self.payment_days and not self.salary_slip_based_on_timesheet:
|
||||
d.amount = 0
|
||||
elif not d.amount:
|
||||
d.amount = d.default_amount
|
||||
@ -277,7 +277,7 @@ class SalarySlip(TransactionBase):
|
||||
def update_status(self, salary_slip=None):
|
||||
for data in self.timesheets:
|
||||
if data.time_sheet:
|
||||
timesheet = frappe.get_doc('Time Sheet', data.time_sheet)
|
||||
timesheet = frappe.get_doc('Timesheet', data.time_sheet)
|
||||
timesheet.salary_slip = salary_slip
|
||||
timesheet.flags.ignore_validate_update_after_submit = True
|
||||
timesheet.set_status()
|
||||
|
@ -23,7 +23,7 @@
|
||||
"label": "Time Sheet",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Time Sheet",
|
||||
"options": "Timesheet",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -71,7 +71,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-06-15 17:59:57.876373",
|
||||
"modified": "2016-07-06 18:35:46.156411",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip Timesheet",
|
||||
|
@ -41,7 +41,7 @@ frappe.ui.form.on("Production Order", {
|
||||
if(frm.doc.docstatus == 1){
|
||||
frm.add_custom_button(__('Make Timesheet'), function(){
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.manufacturing.doctype.production_order.production_order.make_timesheet",
|
||||
method: "erpnext.manufacturing.doctype.production_order.production_order.make_new_timesheet",
|
||||
frm: cur_frm
|
||||
})
|
||||
})
|
||||
@ -125,9 +125,9 @@ erpnext.production_order = {
|
||||
|
||||
// opertions
|
||||
if ((doc.operations || []).length) {
|
||||
frm.add_custom_button(__('Time Sheet'), function() {
|
||||
frm.add_custom_button(__('Timesheet'), function() {
|
||||
frappe.route_options = {"production_order": frm.doc.name};
|
||||
frappe.set_route("List", "Time Sheet");
|
||||
frappe.set_route("List", "Timesheet");
|
||||
}, __("View"));
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
||||
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError, NotInWorkingHoursError
|
||||
from erpnext.projects.doctype.time_sheet.time_sheet import OverlapError
|
||||
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs
|
||||
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||
from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
|
||||
@ -161,10 +161,6 @@ class ProductionOrder(Document):
|
||||
def before_submit(self):
|
||||
self.set_required_items()
|
||||
self.make_time_logs()
|
||||
|
||||
def before_cancel(self):
|
||||
for data in self.operations:
|
||||
data.time_sheet = None
|
||||
|
||||
def on_submit(self):
|
||||
if not self.wip_warehouse:
|
||||
@ -181,7 +177,7 @@ class ProductionOrder(Document):
|
||||
|
||||
frappe.db.set(self,'status', 'Cancelled')
|
||||
self.clear_required_items()
|
||||
self.delete_time_sheet()
|
||||
self.delete_timesheet()
|
||||
self.update_completed_qty_in_material_request()
|
||||
self.update_planned_qty()
|
||||
|
||||
@ -248,10 +244,10 @@ class ProductionOrder(Document):
|
||||
if not self.operations:
|
||||
return
|
||||
|
||||
time_sheets = []
|
||||
timesheets = []
|
||||
plan_days = frappe.db.get_single_value("Manufacturing Settings", "capacity_planning_for_days") or 30
|
||||
|
||||
time_sheet = make_time_sheet(self.name)
|
||||
|
||||
timesheet = make_timesheet(self.name)
|
||||
workstation_list = []
|
||||
last_workstation_idx = {}
|
||||
|
||||
@ -261,18 +257,18 @@ class ProductionOrder(Document):
|
||||
self.set_start_end_time_for_workstation(d, workstation_list, last_workstation_idx.get(d.workstation))
|
||||
|
||||
args = self.get_operations_data(d)
|
||||
add_timesheet_detail(time_sheet, args)
|
||||
add_timesheet_detail(timesheet, args)
|
||||
original_start_time = d.planned_start_time
|
||||
|
||||
# validate operating hours if workstation [not mandatory] is specified
|
||||
self.check_operation_fits_in_working_hours(d)
|
||||
try:
|
||||
time_sheet.validate_time_logs()
|
||||
timesheet.validate_time_logs()
|
||||
except OverlapError:
|
||||
if frappe.message_log: frappe.message_log.pop()
|
||||
time_sheet.move_to_next_non_overlapping_slot(d.idx)
|
||||
timesheet.move_to_next_non_overlapping_slot(d.idx)
|
||||
|
||||
from_time, to_time = self.get_start_end_time(time_sheet, d.name)
|
||||
from_time, to_time = self.get_start_end_time(timesheet, d.name)
|
||||
|
||||
if date_diff(from_time, original_start_time) > plan_days:
|
||||
frappe.throw(_("Unable to find Time Slot in the next {0} days for Operation {1}").format(plan_days, d.operation))
|
||||
@ -281,18 +277,18 @@ class ProductionOrder(Document):
|
||||
d.planned_start_time = from_time
|
||||
d.planned_end_time = to_time
|
||||
d.db_update()
|
||||
|
||||
if time_sheet and open_new:
|
||||
return time_sheet
|
||||
|
||||
if time_sheet:
|
||||
time_sheet.save()
|
||||
time_sheets.append(time_sheet.name)
|
||||
if timesheet and open_new:
|
||||
return timesheet
|
||||
|
||||
if timesheet:
|
||||
timesheet.save()
|
||||
timesheets.append(timesheet.name)
|
||||
|
||||
self.planned_end_date = self.operations[-1].planned_end_time
|
||||
if time_sheets:
|
||||
if timesheets:
|
||||
frappe.local.message_log = []
|
||||
frappe.msgprint(_("Time Sheet created:") + "\n" + "\n".join(time_sheets))
|
||||
frappe.msgprint(_("Timesheet created:") + "\n" + "\n".join(timesheets))
|
||||
|
||||
def get_operations_data(self, data):
|
||||
return {
|
||||
@ -322,8 +318,8 @@ class ProductionOrder(Document):
|
||||
if data.planned_start_time == data.planned_end_time:
|
||||
frappe.throw(_("Capacity Planning Error"))
|
||||
|
||||
def get_start_end_time(self, time_sheet, operation_id):
|
||||
for data in time_sheet.time_logs:
|
||||
def get_start_end_time(self, timesheet, operation_id):
|
||||
for data in timesheet.time_logs:
|
||||
if data.operation_id == operation_id:
|
||||
return data.from_time, data.to_time
|
||||
|
||||
@ -354,9 +350,9 @@ class ProductionOrder(Document):
|
||||
self.actual_start_date = None
|
||||
self.actual_end_date = None
|
||||
|
||||
def delete_time_sheet(self):
|
||||
for time_sheet in frappe.get_all("Time Sheet", ["name"], {"production_order": self.name}):
|
||||
frappe.delete_doc("Time Sheet", time_sheet.name)
|
||||
def delete_timesheet(self):
|
||||
for timesheet in frappe.get_all("Timesheet", ["name"], {"production_order": self.name}):
|
||||
frappe.delete_doc("Timesheet", timesheet.name)
|
||||
|
||||
def validate_production_item(self):
|
||||
if frappe.db.get_value("Item", self.production_item, "has_variants"):
|
||||
@ -508,22 +504,22 @@ def get_events(start, end, filters=None):
|
||||
return data
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_time_sheet(production_order):
|
||||
time_sheet = frappe.new_doc("Time Sheet")
|
||||
time_sheet.employee = ""
|
||||
time_sheet.production_order = production_order
|
||||
return time_sheet
|
||||
def make_timesheet(production_order):
|
||||
timesheet = frappe.new_doc("Timesheet")
|
||||
timesheet.employee = ""
|
||||
timesheet.production_order = production_order
|
||||
return timesheet
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_timesheet_detail(time_sheet, args):
|
||||
if isinstance(time_sheet, unicode):
|
||||
time_sheet = frappe.get_doc('Time Sheet', time_sheet)
|
||||
def add_timesheet_detail(timesheet, args):
|
||||
if isinstance(timesheet, unicode):
|
||||
timesheet = frappe.get_doc('Timesheet', timesheet)
|
||||
|
||||
if isinstance(args, unicode):
|
||||
args = json.loads(args)
|
||||
|
||||
time_sheet.append('time_logs', args)
|
||||
return time_sheet
|
||||
timesheet.append('time_logs', args)
|
||||
return timesheet
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_default_warehouse():
|
||||
@ -534,8 +530,11 @@ def get_default_warehouse():
|
||||
return {"wip_warehouse": wip_warehouse, "fg_warehouse": fg_warehouse}
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_timesheet(source_name, target_doc=None):
|
||||
def make_new_timesheet(source_name, target_doc=None):
|
||||
po = frappe.get_doc('Production Order', source_name)
|
||||
ts = po.make_time_logs(open_new=True)
|
||||
|
||||
|
||||
if not ts.get('time_logs'):
|
||||
frappe.throw(_("Already completed"))
|
||||
|
||||
return ts
|
||||
|
@ -83,8 +83,8 @@ class TestProductionOrder(unittest.TestCase):
|
||||
d = prod_order.operations[0]
|
||||
d.completed_qty = flt(d.completed_qty)
|
||||
|
||||
name = frappe.db.get_value('Time Sheet', {'production_order': prod_order.name}, 'name')
|
||||
time_sheet_doc = frappe.get_doc('Time Sheet', name)
|
||||
name = frappe.db.get_value('Timesheet', {'production_order': prod_order.name}, 'name')
|
||||
time_sheet_doc = frappe.get_doc('Timesheet', name)
|
||||
time_sheet_doc.submit()
|
||||
|
||||
|
||||
|
@ -288,3 +288,4 @@ erpnext.patches.v7_0.update_prevdoc_values_for_supplier_quotation_item
|
||||
erpnext.patches.v7_0.rename_advance_table_fields
|
||||
erpnext.patches.v7_0.rename_salary_components
|
||||
erpnext.patches.v7_0.rename_prevdoc_fields
|
||||
erpnext.patches.v7_0.rename_time_sheet_doctype
|
||||
|
@ -5,7 +5,7 @@ from erpnext.manufacturing.doctype.production_order.production_order import add_
|
||||
def execute():
|
||||
for tlb in frappe.get_all('Time Log Batch', fields=["*"],
|
||||
filters = [["docstatus", "<", "2"]]):
|
||||
time_sheet = frappe.new_doc('Time Sheet')
|
||||
time_sheet = frappe.new_doc('Timesheet')
|
||||
time_sheet.employee= ""
|
||||
time_sheet.company = frappe.db.get_single_value('Global Defaults', 'default_company')
|
||||
time_sheet.sales_invoice = tlb.sales_invoice
|
||||
|
@ -1,7 +1,7 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
for time_sheet in frappe.db.sql(""" select sales_invoice, name, total_billing_amount from `tabTime Sheet`
|
||||
for time_sheet in frappe.db.sql(""" select sales_invoice, name, total_billing_amount from `tabTimesheet`
|
||||
where sales_invoice is not null and docstatus < 2""", as_dict=True):
|
||||
si_doc = frappe.get_doc('Sales Invoice', time_sheet.sales_invoice)
|
||||
ts = si_doc.append('timesheets',{})
|
||||
|
13
erpnext/patches/v7_0/rename_time_sheet_doctype.py
Normal file
13
erpnext/patches/v7_0/rename_time_sheet_doctype.py
Normal file
@ -0,0 +1,13 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
if frappe.db.table_exists("Time Sheet"):
|
||||
frappe.rename_doc("DocType", "Time Sheet", "Timesheet")
|
||||
frappe.rename_doc("DocType", "Time Sheet Detail", "Timesheet Detail")
|
||||
|
||||
for doctype in ['Time Sheet', 'Time Sheet Detail']:
|
||||
frappe.delete_doc('DocType', doctype)
|
||||
|
||||
report = "Daily Time Sheet Summary"
|
||||
if frappe.db.exists("Report", report):
|
||||
frappe.delete_doc('Report', report)
|
@ -7,9 +7,9 @@ import frappe
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('projects', 'doctype','time_sheet')
|
||||
frappe.reload_doc('projects', 'doctype', 'time_sheet_detail')
|
||||
frappe.reload_doc('projects', 'doctype', 'timesheet')
|
||||
frappe.reload_doc('projects', 'doctype', 'timesheet_detail')
|
||||
frappe.reload_doc('accounts', 'doctype', 'sales_invoice_timesheet')
|
||||
|
||||
make_property_setter('Time Sheet', "naming_series", "options", 'TS-', "Text")
|
||||
make_property_setter('Time Sheet', "naming_series", "default", 'TS-', "Text")
|
||||
make_property_setter('Timesheet', "naming_series", "options", 'TS-', "Text")
|
||||
make_property_setter('Timesheet', "naming_series", "default", 'TS-', "Text")
|
@ -19,7 +19,7 @@ class Project(Document):
|
||||
self.load_tasks()
|
||||
|
||||
self.set_onload('activity_summary', frappe.db.sql('''select activity_type, sum(hours) as total_hours
|
||||
from `tabTime Sheet Detail` where project=%s group by activity_type order by total_hours desc''', self.name, as_dict=True))
|
||||
from `tabTimesheet Detail` where project=%s group by activity_type order by total_hours desc''', self.name, as_dict=True))
|
||||
|
||||
def __setup__(self):
|
||||
self.onload()
|
||||
@ -105,7 +105,7 @@ class Project(Document):
|
||||
min(from_time) as start_date,
|
||||
max(to_time) as end_date,
|
||||
sum(hours) as time
|
||||
from `tabTime Sheet Detail` where project = %s and docstatus = 1""", self.name, as_dict=1)[0]
|
||||
from `tabTimesheet Detail` where project = %s and docstatus = 1""", self.name, as_dict=1)[0]
|
||||
|
||||
from_expense_claim = frappe.db.sql("""select
|
||||
sum(total_sanctioned_amount) as total_sanctioned_amount
|
||||
@ -154,7 +154,7 @@ class Project(Document):
|
||||
def get_timeline_data(doctype, name):
|
||||
'''Return timeline for attendance'''
|
||||
return dict(frappe.db.sql('''select unix_timestamp(from_time), count(*)
|
||||
from `tabTime Sheet Detail` where project=%s
|
||||
from `tabTimesheet Detail` where project=%s
|
||||
and from_time > date_sub(curdate(), interval 1 year)
|
||||
and docstatus < 2
|
||||
group by date(from_time)''', name))
|
||||
|
@ -5,7 +5,7 @@ links = {
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Project'),
|
||||
'items': ['Task', 'Time Sheet', 'Expense Claim', 'Issue']
|
||||
'items': ['Task', 'Timesheet', 'Expense Claim', 'Issue']
|
||||
},
|
||||
{
|
||||
'label': _('Material'),
|
||||
|
@ -58,7 +58,7 @@ class Task(Document):
|
||||
def update_time_and_costing(self):
|
||||
tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date,
|
||||
sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
|
||||
sum(hours) as time from `tabTime Sheet Detail` where task = %s and docstatus=1"""
|
||||
sum(hours) as time from `tabTimesheet Detail` where task = %s and docstatus=1"""
|
||||
,self.name, as_dict=1)[0]
|
||||
if self.status == "Open":
|
||||
self.status = "Working"
|
||||
|
@ -7,40 +7,40 @@ import frappe
|
||||
import unittest
|
||||
import datetime
|
||||
from frappe.utils import now_datetime, nowdate
|
||||
from erpnext.projects.doctype.time_sheet.time_sheet import OverlapError
|
||||
from erpnext.projects.doctype.time_sheet.time_sheet import make_salary_slip, make_sales_invoice
|
||||
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
|
||||
from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_sales_invoice
|
||||
|
||||
class TestTimeSheet(unittest.TestCase):
|
||||
def test_time_sheet_billing_amount(self):
|
||||
class TestTimesheet(unittest.TestCase):
|
||||
def test_timesheet_billing_amount(self):
|
||||
salary_structure = make_salary_structure("_T-Employee-0001")
|
||||
time_sheet = make_time_sheet("_T-Employee-0001", True)
|
||||
timesheet = make_timesheet("_T-Employee-0001", True)
|
||||
|
||||
self.assertEquals(time_sheet.total_hours, 2)
|
||||
self.assertEquals(time_sheet.time_logs[0].billing_rate, 50)
|
||||
self.assertEquals(time_sheet.time_logs[0].billing_amount, 100)
|
||||
self.assertEquals(timesheet.total_hours, 2)
|
||||
self.assertEquals(timesheet.time_logs[0].billing_rate, 50)
|
||||
self.assertEquals(timesheet.time_logs[0].billing_amount, 100)
|
||||
|
||||
def test_salary_slip_from_timesheet(self):
|
||||
salary_structure = make_salary_structure("_T-Employee-0001")
|
||||
time_sheet = make_time_sheet("_T-Employee-0001", simulate = True)
|
||||
salary_slip = make_salary_slip(time_sheet.name)
|
||||
timesheet = make_timesheet("_T-Employee-0001", simulate = True)
|
||||
salary_slip = make_salary_slip(timesheet.name)
|
||||
salary_slip.submit()
|
||||
|
||||
self.assertEquals(salary_slip.total_working_hours, 2)
|
||||
self.assertEquals(salary_slip.hour_rate, 50)
|
||||
self.assertEquals(salary_slip.net_pay, 150)
|
||||
self.assertEquals(salary_slip.timesheets[0].time_sheet, time_sheet.name)
|
||||
self.assertEquals(salary_slip.timesheets[0].time_sheet, timesheet.name)
|
||||
self.assertEquals(salary_slip.timesheets[0].working_hours, 2)
|
||||
|
||||
time_sheet = frappe.get_doc('Time Sheet', time_sheet.name)
|
||||
self.assertEquals(time_sheet.status, 'Payslip')
|
||||
timesheet = frappe.get_doc('Timesheet', timesheet.name)
|
||||
self.assertEquals(timesheet.status, 'Payslip')
|
||||
salary_slip.cancel()
|
||||
|
||||
time_sheet = frappe.get_doc('Time Sheet', time_sheet.name)
|
||||
self.assertEquals(time_sheet.status, 'Submitted')
|
||||
timesheet = frappe.get_doc('Timesheet', timesheet.name)
|
||||
self.assertEquals(timesheet.status, 'Submitted')
|
||||
|
||||
def test_sales_invoice_from_timesheet(self):
|
||||
time_sheet = make_time_sheet("_T-Employee-0001", simulate = True, billable = 1)
|
||||
sales_invoice = make_sales_invoice(time_sheet.name)
|
||||
timesheet = make_timesheet("_T-Employee-0001", simulate = True, billable = 1)
|
||||
sales_invoice = make_sales_invoice(timesheet.name)
|
||||
sales_invoice.customer = "_Test Customer"
|
||||
sales_invoice.due_date = nowdate()
|
||||
|
||||
@ -51,9 +51,9 @@ class TestTimeSheet(unittest.TestCase):
|
||||
|
||||
sales_invoice.submit()
|
||||
|
||||
time_sheet = frappe.get_doc('Time Sheet', time_sheet.name)
|
||||
timesheet = frappe.get_doc('Timesheet', timesheet.name)
|
||||
self.assertEquals(sales_invoice.total_billing_amount, 100)
|
||||
self.assertEquals(time_sheet.status, 'Billed')
|
||||
self.assertEquals(timesheet.status, 'Billed')
|
||||
|
||||
def make_salary_structure(employee):
|
||||
name = frappe.db.get_value('Salary Structure', {'employee': employee, 'salary_slip_based_on_timesheet': 1}, 'name')
|
||||
@ -86,34 +86,34 @@ def make_salary_structure(employee):
|
||||
|
||||
return salary_structure
|
||||
|
||||
def make_time_sheet(employee, simulate=False, billable = 0):
|
||||
def make_timesheet(employee, simulate=False, billable = 0):
|
||||
update_activity_type("_Test Activity Type")
|
||||
time_sheet = frappe.new_doc("Time Sheet")
|
||||
time_sheet.employee = employee
|
||||
time_sheet_detail = time_sheet.append('time_logs', {})
|
||||
time_sheet_detail.billable = billable
|
||||
time_sheet_detail.activity_type = "_Test Activity Type"
|
||||
time_sheet_detail.from_time = now_datetime()
|
||||
time_sheet_detail.hours = 2
|
||||
time_sheet_detail.to_time = time_sheet_detail.from_time + datetime.timedelta(hours= time_sheet_detail.hours)
|
||||
timesheet = frappe.new_doc("Timesheet")
|
||||
timesheet.employee = employee
|
||||
timesheet_detail = timesheet.append('time_logs', {})
|
||||
timesheet_detail.billable = billable
|
||||
timesheet_detail.activity_type = "_Test Activity Type"
|
||||
timesheet_detail.from_time = now_datetime()
|
||||
timesheet_detail.hours = 2
|
||||
timesheet_detail.to_time = timesheet_detail.from_time + datetime.timedelta(hours= timesheet_detail.hours)
|
||||
|
||||
for data in time_sheet.get('time_logs'):
|
||||
for data in timesheet.get('time_logs'):
|
||||
if simulate:
|
||||
while True:
|
||||
try:
|
||||
time_sheet.save()
|
||||
timesheet.save()
|
||||
break
|
||||
except OverlapError:
|
||||
data.from_time = data.from_time + datetime.timedelta(minutes=10)
|
||||
data.to_time = data.from_time + datetime.timedelta(hours= data.hours)
|
||||
else:
|
||||
time_sheet.save()
|
||||
timesheet.save()
|
||||
|
||||
time_sheet.submit()
|
||||
timesheet.submit()
|
||||
|
||||
return time_sheet
|
||||
return timesheet
|
||||
|
||||
def update_activity_type(activity_type):
|
||||
activity_type = frappe.get_doc('Activity Type',activity_type)
|
||||
activity_type.billing_rate = 50.0
|
||||
activity_type.save(ignore_permissions=True)
|
||||
activity_type.save(ignore_permissions=True)
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on("Time Sheet", {
|
||||
frappe.ui.form.on("Timesheet", {
|
||||
setup: function(frm) {
|
||||
frm.get_field('time_logs').grid.editable_fields = [
|
||||
{fieldname: 'activity_type', columns: 2},
|
||||
@ -12,7 +12,7 @@ frappe.ui.form.on("Time Sheet", {
|
||||
|
||||
frm.fields_dict.employee.get_query = function() {
|
||||
return {
|
||||
query:"erpnext.projects.doctype.time_sheet.time_sheet.get_employee_list"
|
||||
query:"erpnext.projects.doctype.timesheet.timesheet.get_employee_list"
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,20 +50,20 @@ frappe.ui.form.on("Time Sheet", {
|
||||
|
||||
make_invoice: function(frm) {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.projects.doctype.time_sheet.time_sheet.make_sales_invoice",
|
||||
method: "erpnext.projects.doctype.timesheet.timesheet.make_sales_invoice",
|
||||
frm: frm
|
||||
});
|
||||
},
|
||||
|
||||
make_salary_slip: function(frm) {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.projects.doctype.time_sheet.time_sheet.make_salary_slip",
|
||||
method: "erpnext.projects.doctype.timesheet.timesheet.make_salary_slip",
|
||||
frm: frm
|
||||
});
|
||||
},
|
||||
})
|
||||
|
||||
frappe.ui.form.on("Time Sheet Detail", {
|
||||
frappe.ui.form.on("Timesheet Detail", {
|
||||
time_logs_remove: function(frm) {
|
||||
calculate_time_and_amount(frm);
|
||||
},
|
||||
@ -107,7 +107,7 @@ frappe.ui.form.on("Time Sheet Detail", {
|
||||
child = locals[cdt][cdn];
|
||||
if(frm.doc.employee || frm.doc.production_order){
|
||||
frappe.call({
|
||||
method: "erpnext.projects.doctype.time_sheet.time_sheet.get_activity_cost",
|
||||
method: "erpnext.projects.doctype.timesheet.timesheet.get_activity_cost",
|
||||
args: {
|
||||
employee: frm.doc.employee,
|
||||
activity_type: child.activity_type
|
@ -436,7 +436,7 @@
|
||||
"label": "Time Sheets",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Time Sheet Detail",
|
||||
"options": "Timesheet Detail",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
@ -563,7 +563,7 @@
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Time Sheet",
|
||||
"options": "Timesheet",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
@ -586,10 +586,10 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-06-29 15:16:31.668367",
|
||||
"modified": "2016-07-06 18:36:21.103681",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Time Sheet",
|
||||
"name": "Timesheet",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
@ -1,6 +1,5 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
@ -15,8 +14,7 @@ from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings
|
||||
class OverlapError(frappe.ValidationError): pass
|
||||
class OverProductionLoggedError(frappe.ValidationError): pass
|
||||
|
||||
class TimeSheet(Document):
|
||||
|
||||
class Timesheet(Document):
|
||||
def validate(self):
|
||||
self.set_status()
|
||||
self.total_hours = 0.0
|
||||
@ -117,7 +115,7 @@ class TimeSheet(Document):
|
||||
"""Returns 'Actual Operating Time'. """
|
||||
return frappe.db.sql("""select
|
||||
sum(tsd.hours*60) as mins, sum(tsd.completed_qty) as completed_qty, min(tsd.from_time) as from_time,
|
||||
max(tsd.to_time) as to_time from `tabTime Sheet Detail` as tsd, `tabTime Sheet` as ts where
|
||||
max(tsd.to_time) as to_time from `tabTimesheet Detail` as tsd, `tabTimesheet` as ts where
|
||||
ts.production_order = %s and tsd.operation_id = %s and ts.docstatus=1 and ts.name = tsd.parent""",
|
||||
(self.production_order, operation_id), as_dict=1)[0]
|
||||
|
||||
@ -159,7 +157,7 @@ class TimeSheet(Document):
|
||||
return
|
||||
|
||||
existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
|
||||
`tabTime Sheet Detail` tsd, `tabTime Sheet` ts where tsd.`{0}`=%(val)s and tsd.parent = ts.name and
|
||||
`tabTimesheet Detail` tsd, `tabTimesheet` ts where tsd.`{0}`=%(val)s and tsd.parent = ts.name and
|
||||
(
|
||||
(%(from_time)s > tsd.from_time and %(from_time)s < tsd.to_time) or
|
||||
(%(to_time)s > tsd.from_time and %(to_time)s < tsd.to_time) or
|
||||
@ -198,7 +196,7 @@ class TimeSheet(Document):
|
||||
|
||||
def get_last_working_slot(self, time_sheet, workstation):
|
||||
return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
|
||||
from `tabTime Sheet Detail` where workstation = %(workstation)s""",
|
||||
from `tabTimesheet Detail` where workstation = %(workstation)s""",
|
||||
{'workstation': workstation}, as_dict=True)[0]
|
||||
|
||||
def update_cost(self):
|
||||
@ -216,8 +214,8 @@ class TimeSheet(Document):
|
||||
def make_sales_invoice(source_name, target=None):
|
||||
target = frappe.new_doc("Sales Invoice")
|
||||
|
||||
target.append("timesheets", get_mapped_doc("Time Sheet", source_name, {
|
||||
"Time Sheet": {
|
||||
target.append("timesheets", get_mapped_doc("Timesheet", source_name, {
|
||||
"Timesheet": {
|
||||
"doctype": "Sales Invoice Timesheet",
|
||||
"field_map": {
|
||||
"total_billing_amount": "billing_amount",
|
||||
@ -235,8 +233,8 @@ def make_salary_slip(source_name, target_doc=None):
|
||||
target = frappe.new_doc("Salary Slip")
|
||||
set_missing_values(source_name, target)
|
||||
|
||||
target.append("timesheets", get_mapped_doc("Time Sheet", source_name, {
|
||||
"Time Sheet": {
|
||||
target.append("timesheets", get_mapped_doc("Timesheet", source_name, {
|
||||
"Timesheet": {
|
||||
"doctype": "Salary Slip Timesheet",
|
||||
"field_map": {
|
||||
"total_hours": "working_hours",
|
||||
@ -250,7 +248,7 @@ def make_salary_slip(source_name, target_doc=None):
|
||||
return target
|
||||
|
||||
def set_missing_values(time_sheet, target):
|
||||
doc = frappe.get_doc('Time Sheet', time_sheet)
|
||||
doc = frappe.get_doc('Timesheet', time_sheet)
|
||||
target.employee = doc.employee
|
||||
target.employee_name = doc.employee_name
|
||||
target.salary_slip_based_on_timesheet = 1
|
@ -1,4 +1,4 @@
|
||||
frappe.listview_settings['Time Sheet'] = {
|
||||
frappe.listview_settings['Timesheet'] = {
|
||||
add_fields: ["status", "total_hours"],
|
||||
get_indicator: function(doc) {
|
||||
if (doc.status== "Billed") {
|
@ -531,10 +531,10 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-07-06 13:40:41.419370",
|
||||
"modified": "2016-07-06 18:35:24.106546",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Time Sheet Detail",
|
||||
"name": "Timesheet Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
@ -6,5 +6,5 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class TimeSheetDetail(Document):
|
||||
class TimesheetDetail(Document):
|
||||
pass
|
@ -12,7 +12,7 @@ def execute(filters=None):
|
||||
filters["from_time"] = "00:00:00"
|
||||
filters["to_time"] = "24:00:00"
|
||||
|
||||
columns = [_("Time Sheet") + ":Link/Time Sheet:120", _("Employee") + "::150", _("From Datetime") + "::140",
|
||||
columns = [_("Timesheet") + ":Link/Timesheet:120", _("Employee") + "::150", _("From Datetime") + "::140",
|
||||
_("To Datetime") + "::140", _("Hours") + "::70", _("Activity Type") + "::120", _("Task") + ":Link/Task:150",
|
||||
_("Project") + ":Link/Project:120", _("Status") + "::70"]
|
||||
|
||||
@ -28,7 +28,7 @@ def execute(filters=None):
|
||||
|
||||
def get_data(conditions, filters):
|
||||
time_sheet = frappe.db.sql(""" select ts.name, ts.employee, tsd.from_time, tsd.to_time, tsd.hours,
|
||||
tsd.activity_type, tsd.task, tsd.project, ts.status from `tabTime Sheet Detail` tsd,
|
||||
`tabTime Sheet` ts where ts.name = tsd.parent and %s order by ts.name"""%(conditions), filters, as_list=1)
|
||||
tsd.activity_type, tsd.task, tsd.project, ts.status from `tabTimesheet Detail` tsd,
|
||||
`tabTimesheet` ts where ts.name = tsd.parent and %s order by ts.name"""%(conditions), filters, as_list=1)
|
||||
|
||||
return time_sheet
|
||||
|
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.query_reports["Daily Timesheet Summary"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname":"from_date",
|
||||
"label": __("From Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.datetime.get_today()
|
||||
},
|
||||
{
|
||||
"fieldname":"to_date",
|
||||
"label": __("To Date"),
|
||||
"fieldtype": "Date",
|
||||
"default": frappe.datetime.get_today()
|
||||
},
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2016-07-06 19:31:25.534583",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2016-07-06 19:31:25.534583",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Daily Timesheet Summary",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Timesheet",
|
||||
"report_name": "Daily Timesheet Summary",
|
||||
"report_type": "Script Report"
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters:
|
||||
filters = {}
|
||||
elif filters.get("from_date") or filters.get("to_date"):
|
||||
filters["from_time"] = "00:00:00"
|
||||
filters["to_time"] = "24:00:00"
|
||||
|
||||
columns = [_("Timesheet") + ":Link/Timesheet:120", _("Employee") + "::150", _("From Datetime") + "::140",
|
||||
_("To Datetime") + "::140", _("Hours") + "::70", _("Activity Type") + "::120", _("Task") + ":Link/Task:150",
|
||||
_("Project") + ":Link/Project:120", _("Status") + "::70"]
|
||||
|
||||
conditions = "ts.docstatus = 1"
|
||||
if filters.get("from_date"):
|
||||
conditions += " and tsd.from_time >= timestamp(%(from_date)s, %(from_time)s)"
|
||||
if filters.get("to_date"):
|
||||
conditions += " and tsd.to_time <= timestamp(%(to_date)s, %(to_time)s)"
|
||||
|
||||
data = get_data(conditions, filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_data(conditions, filters):
|
||||
time_sheet = frappe.db.sql(""" select ts.name, ts.employee, tsd.from_time, tsd.to_time, tsd.hours,
|
||||
tsd.activity_type, tsd.task, tsd.project, ts.status from `tabTimesheet Detail` tsd,
|
||||
`tabTimesheet` ts where ts.name = tsd.parent and %s order by ts.name"""%(conditions), filters, as_list=1)
|
||||
|
||||
return time_sheet
|
@ -73,7 +73,7 @@ def delete_bins(company_name):
|
||||
def delete_time_sheets(company_name):
|
||||
# Delete Time Logs as it is linked to Production Order / Project / Task, which are linked to company
|
||||
frappe.db.sql("""
|
||||
delete from `tabTime Sheet`
|
||||
delete from `tabTimesheet`
|
||||
where
|
||||
company=%(company)s
|
||||
""", {"company": company_name})
|
||||
|
@ -45,7 +45,7 @@ def get_domains():
|
||||
},
|
||||
|
||||
'Services': {
|
||||
'desktop_icons': ['Project', 'Time Sheet', 'Customer', 'Sales Order', 'Sales Invoice', 'Lead', 'Opportunity',
|
||||
'desktop_icons': ['Project', 'Timesheet', 'Customer', 'Sales Order', 'Sales Invoice', 'Lead', 'Opportunity',
|
||||
'Expense Claim', 'Employee', 'HR', 'ToDo'],
|
||||
'remove_roles': ['Manufacturing User', 'Manufacturing Manager'],
|
||||
'properties': [
|
||||
|
@ -43,6 +43,6 @@ def get_notification_config():
|
||||
"Purchase Receipt": {"docstatus": 0},
|
||||
"Production Order": { "status": ("in", ("Draft", "Not Started", "In Process")) },
|
||||
"BOM": {"docstatus": 0},
|
||||
"Time Sheet": {"status": "Draft"}
|
||||
"Timesheet": {"status": "Draft"}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user