def set_auto_repeat_period(args, mcount, new_document): if mcount and new_document.meta.get_field( 'from_date') and new_document.meta.get_field('to_date'): last_ref_doc = frappe.db.sql(""" select name, from_date, to_date from `tab{0}` where auto_repeat=%s and docstatus < 2 order by creation desc limit 1 """.format(args.reference_doctype), args.name, as_dict=1) if not last_ref_doc: return from_date = get_next_date(last_ref_doc[0].from_date, mcount) if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and \ (cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date)): to_date = get_last_day( get_next_date(last_ref_doc[0].to_date, mcount)) else: to_date = get_next_date(last_ref_doc[0].to_date, mcount) new_document.set('from_date', from_date) new_document.set('to_date', to_date)
def calculate_amount(self, start_date, end_date): """ start_date, end_date - datetime.datetime.date return - estimated amount to post for given period Calculated based on already booked amount and item service period """ total_months = ( (self.service_end_date.year - self.service_start_date.year) * 12 + (self.service_end_date.month - self.service_start_date.month) + 1) prorate = date_diff(self.service_end_date, self.service_start_date) / date_diff( get_last_day(self.service_end_date), get_first_day(self.service_start_date)) actual_months = rounded(total_months * prorate, 1) already_booked_amount = self.get_item_total() base_amount = self.base_net_amount / actual_months if base_amount + already_booked_amount > self.base_net_amount: base_amount = self.base_net_amount - already_booked_amount if not (get_first_day(start_date) == start_date and get_last_day(end_date) == end_date): partial_month = flt(date_diff(end_date, start_date)) / flt( date_diff(get_last_day(end_date), get_first_day(start_date))) base_amount *= rounded(partial_month, 1) return base_amount
def make_new_document(ref_wrapper, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(ref_wrapper) mcount = month_map[ref_wrapper.recurring_type] from_date = get_next_date(ref_wrapper.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(ref_wrapper.from_date)) == \ cstr(ref_wrapper.from_date)) and \ (cstr(get_last_day(ref_wrapper.to_date)) == \ cstr(ref_wrapper.to_date)): to_date = get_last_day(get_next_date(ref_wrapper.to_date, mcount)) else: to_date = get_next_date(ref_wrapper.to_date, mcount) new_document.update({ date_field: posting_date, "from_date": from_date, "to_date": to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "owner": ref_wrapper.owner, }) if ref_wrapper.doctype == "Sales Order": new_document.update({ "delivery_date": get_next_date(ref_wrapper.delivery_date, mcount, cint(ref_wrapper.repeat_on_day_of_month)) }) new_document.submit() return new_document
def test_empty_dashboard_chart(self): if frappe.db.exists('Dashboard Chart', 'Test Empty Dashboard Chart'): frappe.delete_doc('Dashboard Chart', 'Test Empty Dashboard Chart') frappe.db.sql('delete from `tabError Log`') frappe.get_doc(dict( doctype = 'Dashboard Chart', chart_name = 'Test Empty Dashboard Chart', chart_type = 'Count', document_type = 'Error Log', based_on = 'creation', timespan = 'Last Year', time_interval = 'Monthly', filters_json = '[]', timeseries = 1 )).insert() cur_date = datetime.now() - relativedelta(years=1) result = get(chart_name ='Test Empty Dashboard Chart', refresh=1) self.assertEqual(result.get('labels')[0], formatdate(cur_date.strftime('%Y-%m-%d'))) if formatdate(cur_date.strftime('%Y-%m-%d')) == formatdate(get_last_day(cur_date).strftime('%Y-%m-%d')): cur_date += relativedelta(months=1) for idx in range(1, 13): month = get_last_day(cur_date) month = formatdate(month.strftime('%Y-%m-%d')) self.assertEqual(result.get('labels')[idx], month) cur_date += relativedelta(months=1) frappe.db.rollback()
def make_new_invoice(ref_wrapper, posting_date): from erpnext.accounts.utils import get_fiscal_year new_invoice = frappe.copy_doc(ref_wrapper) mcount = month_map[ref_wrapper.recurring_type] invoice_period_from_date = get_next_date(ref_wrapper.invoice_period_from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(ref_wrapper.invoice_period_from_date)) == \ cstr(ref_wrapper.invoice_period_from_date)) and \ (cstr(get_last_day(ref_wrapper.invoice_period_to_date)) == \ cstr(ref_wrapper.invoice_period_to_date)): invoice_period_to_date = get_last_day(get_next_date(ref_wrapper.invoice_period_to_date, mcount)) else: invoice_period_to_date = get_next_date(ref_wrapper.invoice_period_to_date, mcount) new_invoice.update({ "posting_date": posting_date, "aging_date": posting_date, "due_date": add_days(posting_date, cint(date_diff(ref_wrapper.due_date, ref_wrapper.posting_date))), "invoice_period_from_date": invoice_period_from_date, "invoice_period_to_date": invoice_period_to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "owner": ref_wrapper.owner, }) new_invoice.submit() return new_invoice
def get_next_dep_date(doc, dep_freq, tot_dep): #Next depreciation date shoud be last date of the purchase date if monthly or last date #of period of depreciation #if monthly depreciation then last day or month, if bi-monthly then last day of month+1 #if 3 monthly then last day of quarter and not 3 months #if 4 monthly then last day of third and not 4 months and so on and so forth fy_doc = get_fy_doc(doc) r = relativedelta.relativedelta(add_days(fy_doc.year_end_date, 1), fy_doc.year_start_date) fy_months = r.years * 12 + r.months dep_in_fy = cint(fy_months) / flt(dep_freq) booked_deps_months = (cint(doc.number_of_depreciations_booked) * cint(dep_freq)) last_day = add_months(get_last_day(doc.purchase_date), booked_deps_months) base_last_day = get_last_day(doc.purchase_date) base_dep_date = None if dep_in_fy >= 1 and dep_in_fy % 1 == 0: for i in range(0, cint(tot_dep)): dep_date = get_last_day( add_months(fy_doc.year_start_date, (i * dep_freq - 1))) if base_last_day <= dep_date and base_dep_date is None: base_dep_date = dep_date if last_day <= dep_date: doc.next_depreciation_date = dep_date break else: doc.next_depreciation_date = fy_doc.year_end_date elif dep_in_fy % 1 != 0: frappe.throw( 'Frequency Causing Depreciations not to be posted equally in FY, \ please change the frequency of depreciation') else: frappe.throw('Months between depreciation cannot be less than 1') return base_dep_date
def update_doc(new_document, reference_doc, args, schedule_date): new_document.docstatus = 0 if new_document.meta.get_field('set_posting_time'): new_document.set('set_posting_time', 1) mcount = month_map.get(args.frequency) if new_document.meta.get_field('subscription'): new_document.set('subscription', args.name) if args.from_date and args.to_date: from_date = get_next_date(args.from_date, mcount) if (cstr(get_first_day(args.from_date)) == cstr(args.from_date)) and \ (cstr(get_last_day(args.to_date)) == cstr(args.to_date)): to_date = get_last_day(get_next_date(args.to_date, mcount)) else: to_date = get_next_date(args.to_date, mcount) if new_document.meta.get_field('from_date'): new_document.set('from_date', from_date) new_document.set('to_date', to_date) new_document.run_method("on_recurring", reference_doc=reference_doc, subscription_doc=args) for data in new_document.meta.fields: if data.fieldtype == 'Date' and data.reqd: new_document.set(data.fieldname, schedule_date)
def create_interests(self): get_start_date = compose( frappe.utils.get_first_day, partial(frappe.utils.add_months, self.billing_start_date), ) for i in range(0, self.emi_duration): start_date = self.billing_start_date if i == 0 else get_start_date( i) end_date = get_last_day(start_date) period = start_date.strftime("%b %Y") frappe.get_doc({ "doctype": "Microfinance Loan Interest", "loan": self.name, "posting_date": add_days(end_date, 1), "period": period, "start_date": start_date, "end_date": end_date, "billed_amount": self.monthly_interest, "principal_amount": self.loan_principal / self.emi_duration, }).insert(ignore_permissions=True) self.billing_end_date = get_last_day( frappe.utils.add_months(self.billing_start_date, self.emi_duration))
def make_new_document(ref_wrapper, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(ref_wrapper) mcount = month_map[ref_wrapper.recurring_type] from_date = get_next_date(ref_wrapper.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(ref_wrapper.from_date)) == cstr(ref_wrapper.from_date)) and \ (cstr(get_last_day(ref_wrapper.to_date)) == cstr(ref_wrapper.to_date)): to_date = get_last_day(get_next_date(ref_wrapper.to_date, mcount)) else: to_date = get_next_date(ref_wrapper.to_date, mcount) new_document.update({ date_field: posting_date, "from_date": from_date, "to_date": to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "owner": ref_wrapper.owner, }) if ref_wrapper.doctype == "Sales Order": new_document.update({ "delivery_date": get_next_date(ref_wrapper.delivery_date, mcount, cint(ref_wrapper.repeat_on_day_of_month)) }) new_document.submit() return new_document
def set_auto_repeat_period(self, new_doc): mcount = month_map.get(self.frequency) if mcount and new_doc.meta.get_field("from_date") and new_doc.meta.get_field("to_date"): last_ref_doc = frappe.db.get_all( doctype=self.reference_doctype, fields=["name", "from_date", "to_date"], filters=[ ["auto_repeat", "=", self.name], ["docstatus", "<", 2], ], order_by="creation desc", limit=1, ) if not last_ref_doc: return from_date = get_next_date(last_ref_doc[0].from_date, mcount) if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and ( cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date) ): to_date = get_last_day(get_next_date(last_ref_doc[0].to_date, mcount)) else: to_date = get_next_date(last_ref_doc[0].to_date, mcount) new_doc.set("from_date", from_date) new_doc.set("to_date", to_date)
def validate_employee_advance(employee,date): policies = frappe.get_doc("Advance Salary Policies","Advance Salary Policies") employee_type = frappe.db.get_value("Employee",employee,"employment_type") if employee_type == "Probation": frappe.msgprint(_("Advance Salary Request Apply After Probation Period")) return False start_date = frappe.db.get_value("Employee",employee,"final_confirmation_date") if getdate(start_date) > getdate(date): frappe.msgprint(_("Advance Salary Request Apply After Probation Period")) return False if get_salary_advance_total(employee,date,policies) == True: frappe.msgprint(_("Already Applied Employee Advance In Last 6 Months")) return False sal_st = get_sal_structure(employee) salary_slip = make_salary_slip_custom(sal_st, employee=employee,start_date=get_first_day(date),end_date=add_days(get_first_day(date),19), ignore_permissions=True) if salary_slip.gross_pay > flt(policies.salary_should_be_below_or_equal_to): frappe.msgprint(_("Gross Pay Must Be Less Than or Equal {0}").format(policies.salary_should_be_below_or_equal_to)) return False holiday_list = get_holiday_list_for_employee(employee, False) attendance = get_filtered_date_list(employee, get_first_day(date), add_days(get_first_day(date),19),holiday_list) working_days = date_diff(get_last_day(date),get_first_day(date)) + 1 gross_pay_day = salary_slip.gross_pay / working_days final_working_days = 20 - ((flt(salary_slip.total_working_days)-len(get_holidays_for_employee(employee,get_first_day(date), add_days(get_first_day(date),19)))) - flt(attendance)) gross_pay_eligible_for_advance = (flt(gross_pay_day) * flt(final_working_days)) loan = get_loan_amount(employee,get_first_day(date),get_last_day(date)) return gross_pay_eligible_for_advance,loan
def set_auto_repeat_period(self, new_doc): mcount = month_map.get(self.frequency) if mcount and new_doc.meta.get_field( 'from_date') and new_doc.meta.get_field('to_date'): last_ref_doc = frappe.db.get_all( doctype=self.reference_doctype, fields=['name', 'from_date', 'to_date'], filters=[ ['auto_repeat', '=', self.name], ['docstatus', '<', 2], ], order_by='creation desc', limit=1) if not last_ref_doc: return from_date = get_next_date(last_ref_doc[0].from_date, mcount) if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and \ (cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date)): to_date = get_last_day( get_next_date(last_ref_doc[0].to_date, mcount)) else: to_date = get_next_date(last_ref_doc[0].to_date, mcount) new_doc.set('from_date', from_date) new_doc.set('to_date', to_date)
def get_next_dep_date(doc, dep_freq, tot_dep): #Next depreciation date shoud be last date of the purchase date if monthly or last date #of period of depreciation #if monthly depreciation then last day or month, if bi-monthly then last day of month+1 #if 3 monthly then last day of quarter and not 3 months #if 4 monthly then last day of third and not 4 months and so on and so forth fy_doc = get_fy_doc(doc) r = relativedelta.relativedelta(add_days(fy_doc.year_end_date,1), fy_doc.year_start_date) fy_months = r.years*12 + r.months dep_in_fy = cint(fy_months)/flt(dep_freq) booked_deps_months = (cint(doc.number_of_depreciations_booked)*cint(dep_freq)) last_day = add_months(get_last_day(doc.purchase_date), booked_deps_months) base_last_day = get_last_day(doc.purchase_date) base_dep_date = None if dep_in_fy >= 1 and dep_in_fy % 1 == 0: for i in range(0, cint(tot_dep)): dep_date = get_last_day(add_months(fy_doc.year_start_date, (i*dep_freq -1))) if base_last_day <= dep_date and base_dep_date is None: base_dep_date = dep_date if last_day <= dep_date: doc.next_depreciation_date = dep_date break else: doc.next_depreciation_date = fy_doc.year_end_date elif dep_in_fy % 1 != 0: frappe.throw('Frequency Causing Depreciations not to be posted equally in FY, \ please change the frequency of depreciation') else: frappe.throw('Months between depreciation cannot be less than 1') return base_dep_date
def make_new_document(ref_wrapper, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(ref_wrapper) mcount = month_map[ref_wrapper.recurring_type] from_date = get_next_date(ref_wrapper.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(ref_wrapper.from_date)) == \ cstr(ref_wrapper.from_date)) and \ (cstr(get_last_day(ref_wrapper.to_date)) == \ cstr(ref_wrapper.to_date)): to_date = get_last_day(get_next_date(ref_wrapper.to_date, mcount)) else: to_date = get_next_date(ref_wrapper.to_date, mcount) new_document.update({ date_field: posting_date, "from_date": from_date, "to_date": to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "owner": ref_wrapper.owner, "docstatus": 0, "per_billed": 0, "per_delivered": 0, "billed_amt": 0, "delivery_status": "Not Delivered" }) new_document.set("sales_order_details", []) for item in ref_wrapper.sales_order_details: new_item = new_document.append('sales_order_details', {}) new_item.item_code = item.item_code new_item.qty = item.qty item_price = frappe.db.get_value( 'Item Price', { 'item_code': item.item_code, 'price_list': new_document.selling_price_list }, 'price_list_rate', as_dict=True) if item_price: new_item.rate = item_price.get('price_list_rate', 0) if ref_wrapper.doctype == "Sales Order": new_document.update({ "delivery_date": get_next_date(ref_wrapper.delivery_date, mcount, cint(ref_wrapper.repeat_on_day_of_month)) }) new_document.save() return new_document
def get_due_date(posting_date, term): due_date = None if term.due_date_based_on == "Day(s) after invoice date": due_date = add_days(posting_date, term.credit_days) elif term.due_date_based_on == "Day(s) after the end of the invoice month": due_date = add_days(get_last_day(posting_date), term.credit_days) elif term.due_date_based_on == "Month(s) after the end of the invoice month": due_date = add_months(get_last_day(posting_date), term.credit_months) return due_date
def get_due_date(term, posting_date=None, bill_date=None): due_date = None date = bill_date or posting_date if term.due_date_based_on == "Day(s) after invoice date": due_date = add_days(date, term.credit_days) elif term.due_date_based_on == "Day(s) after the end of the invoice month": due_date = add_days(get_last_day(date), term.credit_days) elif term.due_date_based_on == "Month(s) after the end of the invoice month": due_date = add_months(get_last_day(date), term.credit_months) return due_date
def test_loan_topup(self): pledge = [{"loan_security": "Test Security 1", "qty": 4000.00}] loan_application = create_loan_application("_Test Company", self.applicant, "Demand Loan", pledge) create_pledge(loan_application) loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() first_date = get_first_day(nowdate()) last_date = get_last_day(nowdate()) no_of_days = date_diff(last_date, first_date) + 1 accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) / ( days_in_year(get_datetime().year) * 100) make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) process_loan_interest_accrual_for_demand_loans( posting_date=add_days(last_date, 1)) # Should not be able to create loan disbursement entry before repayment self.assertRaises(frappe.ValidationError, make_loan_disbursement_entry, loan.name, 500000, first_date) repayment_entry = create_repayment_entry( loan.name, self.applicant, add_days(get_last_day(nowdate()), 5), 611095.89) repayment_entry.submit() loan.reload() # After repayment loan disbursement entry should go through make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 16)) # check for disbursement accrual loan_interest_accrual = frappe.db.get_value( "Loan Interest Accrual", { "loan": loan.name, "accrual_type": "Disbursement" }) self.assertTrue(loan_interest_accrual)
def calculate_monthly_amount( doc, item, last_gl_entry, start_date, end_date, total_days, total_booking_days, account_currency ): amount, base_amount = 0, 0 if not last_gl_entry: total_months = ( (item.service_end_date.year - item.service_start_date.year) * 12 + (item.service_end_date.month - item.service_start_date.month) + 1 ) prorate_factor = flt(date_diff(item.service_end_date, item.service_start_date)) / flt( date_diff(get_last_day(item.service_end_date), get_first_day(item.service_start_date)) ) actual_months = rounded(total_months * prorate_factor, 1) already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount( doc, item ) base_amount = flt(item.base_net_amount / actual_months, item.precision("base_net_amount")) if base_amount + already_booked_amount > item.base_net_amount: base_amount = item.base_net_amount - already_booked_amount if account_currency == doc.company_currency: amount = base_amount else: amount = flt(item.net_amount / actual_months, item.precision("net_amount")) if amount + already_booked_amount_in_account_currency > item.net_amount: amount = item.net_amount - already_booked_amount_in_account_currency if not (get_first_day(start_date) == start_date and get_last_day(end_date) == end_date): partial_month = flt(date_diff(end_date, start_date)) / flt( date_diff(get_last_day(end_date), get_first_day(start_date)) ) base_amount = rounded(partial_month, 1) * base_amount amount = rounded(partial_month, 1) * amount else: already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount( doc, item ) base_amount = flt( item.base_net_amount - already_booked_amount, item.precision("base_net_amount") ) if account_currency == doc.company_currency: amount = base_amount else: amount = flt( item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount") ) return amount, base_amount
def get_pro_rata_amt(row, depreciation_amount, from_date, to_date): months = month_diff(to_date, from_date) if row.depreciation_method == "Prorated Straight Line (360 Days)": todate = get_last_day(from_date) if getdate(to_date).month == 12 else to_date fromdate = get_last_day(to_date) if getdate(from_date).month == 12 else from_date days = date_diff(todate, fromdate) + (cint(months) - 1) * 30 total_days = min(get_total_days(to_date, row.frequency_of_depreciation), 360) else: total_days = get_total_days(to_date, row.frequency_of_depreciation) days = date_diff(to_date, from_date) return (depreciation_amount * flt(days)) / flt(total_days), days, months
def make_new_document(reference_doc, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(reference_doc, ignore_no_copy=True) mcount = month_map[reference_doc.recurring_type] from_date = get_next_date(reference_doc.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(reference_doc.from_date)) == cstr(reference_doc.from_date)) and \ (cstr(get_last_day(reference_doc.to_date)) == cstr(reference_doc.to_date)): to_date = get_last_day(get_next_date(reference_doc.to_date, mcount)) else: to_date = get_next_date(reference_doc.to_date, mcount) new_document.update({ date_field: posting_date, "from_date": from_date, "to_date": to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "next_date": get_next_date(from_date, mcount, cint(reference_doc.repeat_on_day_of_month)) }) # copy document fields for fieldname in ("owner", "recurring_type", "repeat_on_day_of_month", "recurring_id", "notification_email_address", "is_recurring", "end_date", "title", "naming_series", "select_print_heading", "ignore_pricing_rule", "posting_time", "remarks", 'submit_on_creation'): if new_document.meta.get_field(fieldname): new_document.set(fieldname, reference_doc.get(fieldname)) # copy item fields for i, item in enumerate(new_document.items): for fieldname in ("page_break", ): item.set(fieldname, reference_doc.items[i].get(fieldname)) new_document.run_method("on_recurring", reference_doc=reference_doc) if reference_doc.submit_on_creation: new_document.submit() else: new_document.docstatus = 0 new_document.insert() return new_document
def get_plan_rate(plan, quantity=1, customer=None, start_date=None, end_date=None, prorate_factor=1): plan = frappe.get_doc("Subscription Plan", plan) if plan.price_determination == "Fixed Rate": return plan.cost * prorate_factor elif plan.price_determination == "Based On Price List": if customer: customer_group = frappe.db.get_value("Customer", customer, "customer_group") else: customer_group = None price = get_price(item_code=plan.item, price_list=plan.price_list, customer_group=customer_group, company=None, qty=quantity) if not price: return 0 else: return price.price_list_rate * prorate_factor elif plan.price_determination == 'Monthly Rate': start_date = getdate(start_date) end_date = getdate(end_date) no_of_months = (end_date.year - start_date.year) * 12 + ( end_date.month - start_date.month) + 1 cost = plan.cost * no_of_months # Adjust cost if start or end date is not month start or end prorate = frappe.db.get_single_value('Subscription Settings', 'prorate') if prorate: prorate_factor = flt( date_diff(start_date, get_first_day(start_date)) / date_diff(get_last_day(start_date), get_first_day(start_date)), 1) prorate_factor += flt( date_diff(get_last_day(end_date), end_date) / date_diff(get_last_day(end_date), get_first_day(end_date)), 1) cost -= (plan.cost * prorate_factor) return cost
def test_loan_topup(self): pledges = [] pledges.append({ "loan_security": "Test Security 1", "qty": 4000.00, "haircut": 50, "loan_security_price": 500.00 }) loan_security_pledge = create_loan_security_pledge( self.applicant, pledges) loan = create_demand_loan(self.applicant, "Demand Loan", loan_security_pledge.name, posting_date=get_first_day(nowdate())) loan.submit() first_date = get_first_day(nowdate()) last_date = get_last_day(nowdate()) no_of_days = date_diff(last_date, first_date) + 1 accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \ / (days_in_year(get_datetime().year) * 100) make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) process_loan_interest_accrual(posting_date=add_days(last_date, 1)) # Paid 511095.89 amount includes 5,00,000 principal amount and 11095.89 interest amount repayment_entry = create_repayment_entry( loan.name, self.applicant, add_days(get_last_day(nowdate()), 5), "Regular Payment", 611095.89) repayment_entry.submit() loan.reload() make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 16)) total_principal_paid = loan.total_principal_paid loan.reload() # Loan Topup will result in decreasing the Total Principal Paid self.assertEqual(flt(loan.total_principal_paid, 2), flt(total_principal_paid - 500000, 2))
def make_new_document(ref_wrapper, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(ref_wrapper) mcount = month_map[ref_wrapper.recurring_type] from_date = get_next_date(ref_wrapper.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(ref_wrapper.from_date)) == cstr(ref_wrapper.from_date)) and \ (cstr(get_last_day(ref_wrapper.to_date)) == cstr(ref_wrapper.to_date)): to_date = get_last_day(get_next_date(ref_wrapper.to_date, mcount)) else: to_date = get_next_date(ref_wrapper.to_date, mcount)
def validate_asset_finance_books(self, row): if flt(row.expected_value_after_useful_life) >= flt(self.gross_purchase_amount): frappe.throw(_("Row {0}: Expected Value After Useful Life must be less than Gross Purchase Amount") .format(row.idx)) if not row.depreciation_start_date: if not self.available_for_use_date: frappe.throw(_("Row {0}: Depreciation Start Date is required").format(row.idx)) row.depreciation_start_date = get_last_day(self.available_for_use_date) if not self.is_existing_asset: self.opening_accumulated_depreciation = 0 self.number_of_depreciations_booked = 0 else: depreciable_amount = flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) if flt(self.opening_accumulated_depreciation) > depreciable_amount: frappe.throw(_("Opening Accumulated Depreciation must be less than equal to {0}") .format(depreciable_amount)) if self.opening_accumulated_depreciation: if not self.number_of_depreciations_booked: frappe.throw(_("Please set Number of Depreciations Booked")) else: self.number_of_depreciations_booked = 0 if cint(self.number_of_depreciations_booked) > cint(row.total_number_of_depreciations): frappe.throw(_("Number of Depreciations Booked cannot be greater than Total Number of Depreciations")) if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.purchase_date): frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Purchase Date") .format(row.idx)) if row.depreciation_start_date and getdate(row.depreciation_start_date) < getdate(self.available_for_use_date): frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date") .format(row.idx))
def test_create_asset_maintenance(self): pr = make_purchase_receipt(item_code="Photocopier", qty=1, rate=100000.0, location="Test Location") asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_doc = frappe.get_doc('Asset', asset_name) month_end_date = get_last_day(nowdate()) purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) asset_doc.available_for_use_date = purchase_date asset_doc.purchase_date = purchase_date asset_doc.calculate_depreciation = 1 asset_doc.append("finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset_doc.save() if not frappe.db.exists("Asset Maintenance", "Photocopier"): asset_maintenance = frappe.get_doc({ "doctype": "Asset Maintenance", "asset_name": "Photocopier", "maintenance_team": "Team Awesome", "company": "_Test Company", "asset_maintenance_tasks": get_maintenance_tasks() }).insert() next_due_date = calculate_next_due_date(nowdate(), "Monthly") self.assertEqual(asset_maintenance.asset_maintenance_tasks[0].next_due_date, next_due_date)
def get_booking_dates(doc, item, posting_date=None): if not posting_date: posting_date = add_days(today(), -1) last_gl_entry = False deferred_account = "deferred_revenue_account" if doc.doctype=="Sales Invoice" else "deferred_expense_account" prev_gl_entry = frappe.db.sql(''' select name, posting_date from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s order by posting_date desc limit 1 ''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True) if prev_gl_entry: start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1)) else: start_date = item.service_start_date end_date = get_last_day(start_date) if end_date >= item.service_end_date: end_date = item.service_end_date last_gl_entry = True elif item.service_stop_date and end_date >= item.service_stop_date: end_date = item.service_stop_date last_gl_entry = True if end_date > getdate(posting_date): end_date = posting_date if getdate(start_date) <= getdate(end_date): return start_date, end_date, last_gl_entry else: return None, None, None
def execute(filters=None): if not filters: filters = {} from_date = get_first_day(filters["month"] + '-' + filters["year"]) to_date = get_last_day(filters["month"] + '-' + filters["year"]) total_days_in_month = date_diff(to_date, from_date) +1 columns = get_columns(total_days_in_month) students = get_student_group_students(filters.get("student_group"),1) students_list = get_students_list(students) att_map = get_attendance_list(from_date, to_date, filters.get("student_group"), students_list) data = [] for stud in students: row = [stud.student, stud.student_name] student_status = frappe.db.get_value("Student", stud.student, "enabled") date = from_date total_p = total_a = 0.0 for day in range(total_days_in_month): status="None" if att_map.get(stud.student): status = att_map.get(stud.student).get(date, "None") elif not student_status: status = "Inactive" else: status = "None" status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-"} row.append(status_map[status]) if status == "Present": total_p += 1 elif status == "Absent": total_a += 1 date = add_days(date, 1) row += [total_p, total_a] data.append(row) return columns, data
def _test(i): obj.assertEquals(i+1, frappe.db.sql("""select count(*) from `tab%s` where recurring_id=%s and (docstatus=1 or docstatus=0)""" % (base_doc.doctype, '%s'), (base_doc.recurring_id))[0][0]) next_date = get_next_date(base_doc.get(date_field), no_of_months, base_doc.repeat_on_day_of_month) manage_recurring_documents(base_doc.doctype, next_date=next_date, commit=False) recurred_documents = frappe.db.sql("""select name from `tab%s` where recurring_id=%s and (docstatus=1 or docstatus=0) order by name desc""" % (base_doc.doctype, '%s'), (base_doc.recurring_id)) obj.assertEquals(i+2, len(recurred_documents)) new_doc = frappe.get_doc(base_doc.doctype, recurred_documents[0][0]) for fieldname in ["is_recurring", "recurring_type", "repeat_on_day_of_month", "notification_email_address"]: obj.assertEquals(base_doc.get(fieldname), new_doc.get(fieldname)) obj.assertEquals(new_doc.get(date_field), getdate(next_date)) obj.assertEquals(new_doc.from_date, getdate(add_months(base_doc.from_date, no_of_months))) if first_and_last_day: obj.assertEquals(new_doc.to_date, getdate(get_last_day(add_months(base_doc.to_date, no_of_months)))) else: obj.assertEquals(new_doc.to_date, getdate(add_months(base_doc.to_date, no_of_months))) return new_doc
def validate_expense_against_budget(args): args = frappe._dict(args) if not args.cost_center: return if frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"}): cc_lft, cc_rgt = frappe.db.get_value("Cost Center", args.cost_center, ["lft", "rgt"]) budget_records = frappe.db.sql(""" select ba.budget_amount, b.monthly_distribution, b.cost_center, b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded from `tabBudget` b, `tabBudget Account` ba where b.name=ba.parent and b.fiscal_year=%s and ba.account=%s and b.docstatus=1 and exists(select name from `tabCost Center` where lft<=%s and rgt>=%s and name=b.cost_center) """, (args.fiscal_year, args.account, cc_lft, cc_rgt), as_dict=True) for budget in budget_records: if budget.budget_amount: yearly_action = budget.action_if_annual_budget_exceeded monthly_action = budget.action_if_accumulated_monthly_budget_exceeded if monthly_action in ["Stop", "Warn"]: budget_amount = get_accumulated_monthly_budget(budget.monthly_distribution, args.posting_date, args.fiscal_year, budget.budget_amount) args["month_end_date"] = get_last_day(args.posting_date) compare_expense_with_budget(args, budget.cost_center, budget_amount, _("Accumulated Monthly"), monthly_action) if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \ and yearly_action != monthly_action: compare_expense_with_budget(args, budget.cost_center, flt(budget.budget_amount), _("Annual"), yearly_action)
def test_current_asset_value(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_doc = frappe.get_doc('Asset', asset_name) month_end_date = get_last_day(nowdate()) purchase_date = nowdate() if nowdate() != month_end_date else add_days( nowdate(), -15) asset_doc.available_for_use_date = purchase_date asset_doc.purchase_date = purchase_date asset_doc.calculate_depreciation = 1 asset_doc.append( "finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset_doc.submit() current_value = get_current_asset_value(asset_doc.name) self.assertEqual(current_value, 100000.0)
def copy_timesheet_for_rest_day(name): time_sheet_doc = frappe.get_doc("Timesheet", name) last_day = get_last_day(time_sheet_doc.start_date) cur_date = add_days(time_sheet_doc.start_date, 1) count = 1 while getdate(last_day) >= getdate(cur_date): time_dict = [] for row in time_sheet_doc.time_logs: time_json = {} time_json["activity_type"] = row.activity_type time_json["from_time"] = add_days(row.from_time, count) time_json["to_time"] = add_days(row.to_time, count) time_dict.append(time_json) doc = frappe.get_doc( dict(doctype="Timesheet", employee=time_sheet_doc.employee, company=time_sheet_doc.company, time_logs=time_dict)).insert() timesheet_submit_on_duplicate = frappe.db.get_value( "Global FM Setting", "Global FM Setting", "timesheet_submit_on_duplicate") if int(timesheet_submit_on_duplicate) == 1: doc.submit() cur_date = add_days(cur_date, 1) count += 1 frappe.msgprint(str(count) + " Timesheet Added")
def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True): deducted_dates = [] i = 0 while i < 12: slip = frappe.get_doc({ "doctype": "Salary Slip", "employee": employee, "salary_structure": salary_structure, "frequency": "Monthly" }) if i == 0: posting_date = add_days(payroll_period.start_date, 25) else: posting_date = add_months(posting_date, 1) if i == 11: slip.deduct_tax_for_unsubmitted_tax_exemption_proof = 1 slip.deduct_tax_for_unclaimed_employee_benefits = 1 if deduct_random and not random.randint(0, 2): slip.deduct_tax_for_unsubmitted_tax_exemption_proof = 1 deducted_dates.append(posting_date) slip.posting_date = posting_date slip.start_date = get_first_day(posting_date) slip.end_date = get_last_day(posting_date) doc = make_salary_slip(salary_structure, slip, employee) doc.submit() i += 1 return deducted_dates
def test_empty_dashboard_chart(self): if frappe.db.exists("Dashboard Chart", "Test Empty Dashboard Chart"): frappe.delete_doc("Dashboard Chart", "Test Empty Dashboard Chart") frappe.db.sql("delete from `tabError Log`") frappe.get_doc( dict( doctype="Dashboard Chart", chart_name="Test Empty Dashboard Chart", chart_type="Count", document_type="Error Log", based_on="creation", timespan="Last Year", time_interval="Monthly", filters_json="[]", timeseries=1, )).insert() cur_date = datetime.now() - relativedelta(years=1) result = get(chart_name="Test Empty Dashboard Chart", refresh=1) for idx in range(13): month = get_last_day(cur_date) month = formatdate(month.strftime("%Y-%m-%d")) self.assertEqual(result.get("labels")[idx], get_period(month)) cur_date += relativedelta(months=1) frappe.db.rollback()
def test_earned_leave_allocation(self): leave_period = create_leave_period("Test Earned Leave Period") leave_type = create_earned_leave_type("Test Earned Leave") leave_policy = frappe.get_doc({ "doctype": "Leave Policy", "title": "Test Leave Policy", "leave_policy_details": [{ "leave_type": leave_type.name, "annual_allocation": 6 }], }).submit() data = { "assignment_based_on": "Leave Period", "leave_policy": leave_policy.name, "leave_period": leave_period.name, } # second last day of the month # leaves allocated should be 0 since it is an earned leave and allocation happens via scheduler based on set frequency frappe.flags.current_date = add_days(get_last_day(getdate()), -1) leave_policy_assignments = create_assignment_for_multiple_employees( [self.employee.name], frappe._dict(data)) leaves_allocated = frappe.db.get_value( "Leave Allocation", {"leave_policy_assignment": leave_policy_assignments[0]}, "total_leaves_allocated", ) self.assertEqual(leaves_allocated, 0)
def test_dashboard_chart(self): if frappe.db.exists('Dashboard Chart', 'Test Dashboard Chart'): frappe.delete_doc('Dashboard Chart', 'Test Dashboard Chart') frappe.get_doc( dict(doctype='Dashboard Chart', chart_name='Test Dashboard Chart', chart_type='Count', document_type='DocType', based_on='creation', timespan='Last Year', time_interval='Monthly', filters_json='{}', timeseries=1)).insert() cur_date = datetime.now() - relativedelta(years=1) result = get(chart_name='Test Dashboard Chart', refresh=1) for idx in range(13): month = get_last_day(cur_date) month = formatdate(month.strftime('%Y-%m-%d')) self.assertEqual(result.get('labels')[idx], get_period(month)) cur_date += relativedelta(months=1) frappe.db.rollback()
def sms_limit(doc, method=None): limitations = frappe.get_single("Site Limitations") if not limitations.enable or not limitations.sms_restrictions: return allowed_sms = limitations.sms_allowed today = getdate() end_day = get_last_day(today) start_day = get_first_day(today) if limitations.enable_sms_dates: end_day = limitations.sms_to_date start_day = limitations.sms_from_date query = """ SELECT COUNT(name) FROM `tabSMS Log` WHERE DATE(sent_on) BETWEEN '{start_day}' AND '{end_day}' """.format(start_day=start_day, end_day=end_day) sms_list = frappe.db.sql(query, as_dict=True) sms_count = sms_list[0]['COUNT(name)'] contact = frappe.get_value("ISupport Settings", None, "support_email") or "System Administrator" if sms_count > allowed_sms: frappe.throw( 'Only {} SMS allowed and you have sent {} SMS. To increase the limit please contact {}' .format(allowed_sms, sms_count, contact))
def update_late_fees(customer): now_date = datetime.now().date() firstDay_of_month = date(now_date.year, now_date.month, 1) last_day_of_month = get_last_day(now_date) # Get All Open Agreement of Customer customer_agreements = frappe.db.sql("""select name from `tabCustomer Agreement` where agreement_status = "Open" and late_fees_updated="No" and customer = '{0}'""".format(customer),as_list=1) firstDay_this_month = date(now_date.year, now_date.month, 1) for agreement in customer_agreements: total_late_fees = 0 agreement_doc =frappe.get_doc("Customer Agreement",agreement[0]) for row in agreement_doc.payments_record: if row.check_box_of_submit == 0 and getdate(row.due_date) >= firstDay_of_month and getdate(row.due_date) <= now_date: if date_diff(now_date,row.due_date) > 3: no_of_late_days = date_diff(now_date,row.due_date) - 3 row.late_fee_for_payment = "{0:.2f}".format(float(no_of_late_days * agreement_doc.monthly_rental_payment * (agreement_doc.late_fees_rate/100))) total_late_fees = float(total_late_fees) + float(row.late_fee_for_payment) if (row.pre_select_uncheck == 0 and row.check_box_of_submit == 0 and getdate(row.due_date) < firstDay_this_month): if date_diff(now_date,row.due_date) > 3: no_of_late_days = date_diff(now_date,row.due_date) - 3 row.late_fee_for_payment = "{0:.2f}".format(float(no_of_late_days * agreement_doc.monthly_rental_payment * (agreement_doc.late_fees_rate/100))) total_late_fees = float(total_late_fees) + float(row.late_fee_for_payment) agreement_doc.late_fees = total_late_fees agreement_doc.save(ignore_permissions = True)
def make_new_document(reference_doc, date_field, posting_date): from erpnext.accounts.utils import get_fiscal_year new_document = frappe.copy_doc(reference_doc, ignore_no_copy=True) mcount = month_map[reference_doc.recurring_type] from_date = get_next_date(reference_doc.from_date, mcount) # get last day of the month to maintain period if the from date is first day of its own month # and to date is the last day of its own month if (cstr(get_first_day(reference_doc.from_date)) == cstr(reference_doc.from_date)) and \ (cstr(get_last_day(reference_doc.to_date)) == cstr(reference_doc.to_date)): to_date = get_last_day(get_next_date(reference_doc.to_date, mcount)) else: to_date = get_next_date(reference_doc.to_date, mcount) new_document.update({ date_field: posting_date, "from_date": from_date, "to_date": to_date, "fiscal_year": get_fiscal_year(posting_date)[0], "next_date": get_next_date(from_date, mcount,cint(reference_doc.repeat_on_day_of_month)) }) # copy document fields for fieldname in ("owner", "recurring_type", "repeat_on_day_of_month", "recurring_id", "notification_email_address", "is_recurring", "end_date", "title", "naming_series", "select_print_heading", "ignore_pricing_rule", "posting_time", "remarks", 'submit_on_creation'): if new_document.meta.get_field(fieldname): new_document.set(fieldname, reference_doc.get(fieldname)) # copy item fields for i, item in enumerate(new_document.items): for fieldname in ("page_break",): item.set(fieldname, reference_doc.items[i].get(fieldname)) new_document.run_method("on_recurring", reference_doc=reference_doc) if reference_doc.submit_on_creation: new_document.submit() else: new_document.docstatus=0 new_document.insert() return new_document
def get_employee_holidays(self): first_day = get_first_day(self.att_date) last_day = get_last_day(self.att_date) holidays = frappe.db.sql("""select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = %s and t1.holiday_date between %s and %s""",(self.employee, first_day, last_day)) holidays = [cstr(i[0]) for i in holidays] if self.status in ('Weekly Off', 'Public Holiday') and self.att_date not in holidays: frappe.throw(_("This date not present in Holiday list.Please select correct date.."))
def get_due_date_from_template(template_name, posting_date, bill_date): """ Inspects all `Payment Term`s from the a `Payment Terms Template` and returns the due date after considering all the `Payment Term`s requirements. :param template_name: Name of the `Payment Terms Template` :return: String representing the calculated due date """ due_date = getdate(bill_date or posting_date) template = frappe.get_doc('Payment Terms Template', template_name) for term in template.terms: if term.due_date_based_on == 'Day(s) after invoice date': due_date = max(due_date, add_days(due_date, term.credit_days)) elif term.due_date_based_on == 'Day(s) after the end of the invoice month': due_date = max(due_date, add_days(get_last_day(due_date), term.credit_days)) else: due_date = max(due_date, add_months(get_last_day(due_date), term.credit_months)) return due_date
def set_subscription_period(args, mcount, new_document): if mcount and new_document.meta.get_field('from_date') and new_document.meta.get_field('to_date'): last_ref_doc = frappe.db.sql(""" select name, from_date, to_date from `tab{0}` where subscription=%s and docstatus < 2 order by creation desc limit 1 """.format(args.reference_doctype), args.name, as_dict=1) if not last_ref_doc: return from_date = get_next_date(last_ref_doc[0].from_date, mcount) if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and \ (cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date)): to_date = get_last_day(get_next_date(last_ref_doc[0].to_date, mcount)) else: to_date = get_next_date(last_ref_doc[0].to_date, mcount) new_document.set('from_date', from_date) new_document.set('to_date', to_date)
def test_purchase_asset(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset = frappe.get_doc('Asset', asset_name) asset.calculate_depreciation = 1 month_end_date = get_last_day(nowdate()) purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) asset.available_for_use_date = purchase_date asset.purchase_date = purchase_date asset.append("finance_books", { "expected_value_after_useful_life": 10000, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset.submit() pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount, asset.company, asset.purchase_date) pi.supplier = "_Test Supplier" pi.insert() pi.submit() asset.load_from_db() self.assertEqual(asset.supplier, "_Test Supplier") self.assertEqual(asset.purchase_date, getdate(purchase_date)) self.assertEqual(asset.purchase_invoice, pi.name) expected_gle = ( ("Asset Received But Not Billed - _TC", 100000.0, 0.0), ("Creditors - _TC", 0.0, 100000.0) ) gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no = %s order by account""", pi.name) self.assertEqual(gle, expected_gle) pi.cancel() asset.load_from_db() self.assertEqual(asset.supplier, None) self.assertEqual(asset.purchase_invoice, None) self.assertFalse(frappe.db.get_value("GL Entry", {"voucher_type": "Purchase Invoice", "voucher_no": pi.name}))
def make_depreciation_schedule(self): self.schedules = [] done = "" if not self.get("schedules") and self.next_depreciation_date: accumulated_depreciation = flt(self.opening_accumulated_depreciation) income_accumulated_depreciation = flt(self.income_tax_opening_depreciation_amount) value_after_depreciation = flt(self.value_after_depreciation) current_value_income_tax = flt(self.value_after_depreciation) - flt(self.expected_value_after_useful_life) number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \ cint(self.number_of_depreciations_booked) if number_of_pending_depreciations: for n in xrange(number_of_pending_depreciations): schedule_date = get_last_day(add_months(self.next_depreciation_date, n * cint(self.frequency_of_depreciation))) last_schedule_date = add_months(self.next_depreciation_date, (n - 1) * cint(self.frequency_of_depreciation)) if n == 0: num_of_days = get_number_of_days(self.purchase_date, schedule_date) + 1 else: num_of_days = get_number_of_days(last_schedule_date, schedule_date) depreciation_amount = self.get_depreciation_amount(value_after_depreciation, num_of_days) income_tax_amount = self.get_income_tax_depreciation_amount(current_value_income_tax, flt(self.asset_depreciation_percent), num_of_days) accumulated_depreciation += flt(depreciation_amount) value_after_depreciation -= flt(depreciation_amount) income_accumulated_depreciation += income_tax_amount if accumulated_depreciation < self.gross_purchase_amount: self.append("schedules", { "schedule_date": schedule_date, "depreciation_amount": depreciation_amount, "depreciation_income_tax": income_tax_amount, "accumulated_depreciation_amount": accumulated_depreciation, "accumulated_depreciation_income_tax": income_accumulated_depreciation }) else: self.append("schedules", { "schedule_date": schedule_date, "depreciation_amount": flt(self.gross_purchase_amount) - flt(accumulated_depreciation) + flt(self.expected_value_after_useful_life) + flt(depreciation_amount), "depreciation_income_tax": income_tax_amount, "accumulated_depreciation_amount": flt(self.gross_purchase_amount) - flt(self.expected_value_after_useful_life), "accumulated_depreciation_income_tax": income_accumulated_depreciation }) break
def validate_budget_records(args, budget_records): for budget in budget_records: if flt(budget.budget_amount): yearly_action = budget.action_if_annual_budget_exceeded monthly_action = budget.action_if_accumulated_monthly_budget_exceeded if monthly_action in ["Stop", "Warn"]: budget_amount = get_accumulated_monthly_budget(budget.monthly_distribution, args.posting_date, args.fiscal_year, budget.budget_amount) args["month_end_date"] = get_last_day(args.posting_date) compare_expense_with_budget(args, budget_amount, _("Accumulated Monthly"), monthly_action, budget.budget_against) if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \ and yearly_action != monthly_action: compare_expense_with_budget(args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against)
def test_movement_for_serialized_asset(self): asset_item = "Test Serialized Asset Item" pr = make_purchase_receipt(item_code=asset_item, rate = 1000, qty=3, location = "Mumbai") asset_name = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name') asset = frappe.get_doc('Asset', asset_name) month_end_date = get_last_day(nowdate()) asset.available_for_use_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) asset.calculate_depreciation = 1 asset.append("finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset.submit() serial_nos = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'serial_no') mov1 = create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company, source_location = "Mumbai", target_location="Pune", serial_no=serial_nos) self.assertEqual(mov1.target_location, "Pune") serial_no = frappe.db.get_value('Serial No', {'asset': asset_name}, 'name') employee = make_employee("*****@*****.**") create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company, serial_no=serial_no, to_employee=employee) self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), employee) create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company, serial_no=serial_no, from_employee=employee, to_employee="_T-Employee-00001") self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Pune") mov4 = create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company, source_location = "Pune", target_location="Nagpur", serial_no=serial_nos) self.assertEqual(mov4.target_location, "Nagpur") self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Nagpur") self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), "_T-Employee-00001")
def validate_expense_against_budget(args): args = frappe._dict(args) if args.against_voucher_type == 'Asset': pass elif frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"}) or frappe.db.get_value("Account", {"name": args.account, "root_type": "Asset", "account_type": "Fixed Asset"}): cc_lft, cc_rgt = frappe.db.get_value("Cost Center", args.cost_center, ["lft", "rgt"]) budget_records = frappe.db.sql(""" select ba.budget_amount, b.monthly_distribution, b.cost_center, b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded from `tabBudget` b, `tabBudget Account` ba where b.name=ba.parent and b.fiscal_year=%s and ba.account=%s and b.docstatus=1 and exists(select name from `tabCost Center` where lft<=%s and rgt>=%s and name=b.cost_center) """, (args.fiscal_year, args.account, cc_lft, cc_rgt), as_dict=True) if budget_records: for budget in budget_records: if budget.budget_amount: yearly_action = budget.action_if_annual_budget_exceeded monthly_action = budget.action_if_accumulated_monthly_budget_exceeded if monthly_action in ["Stop", "Warn"]: budget_amount = get_accumulated_monthly_budget(budget.monthly_distribution, args.posting_date, args.fiscal_year, budget.budget_amount) args["month_end_date"] = get_last_day(args.posting_date) compare_expense_with_budget(args, budget.cost_center, budget_amount, _("Accumulated Monthly"), monthly_action) if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \ and yearly_action != monthly_action: compare_expense_with_budget(args, budget.cost_center, flt(budget.budget_amount), _("Annual"), yearly_action) elif args.account in ['Normal Loss - SMCL', 'Abnormal Loss - SMCL', 'Cost of Good Manufacture - SMCL', 'Stripping Cost Amortization - SMCL']: pass elif str(frappe.db.get_value("Account", args.account, "parent_account")) == "Depreciation & Amortisation - SMCL": pass else: #Budget Check if there is no budget booking under the budget head frappe.throw("There is no budget in " + args.account + " under " + args.cost_center + " for " + str(args.fiscal_year))
def test_asset_depreciation_value_adjustment(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_doc = frappe.get_doc('Asset', asset_name) asset_doc.calculate_depreciation = 1 month_end_date = get_last_day(nowdate()) purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) asset_doc.available_for_use_date = purchase_date asset_doc.purchase_date = purchase_date asset_doc.calculate_depreciation = 1 asset_doc.append("finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset_doc.submit() current_value = get_current_asset_value(asset_doc.name) adj_doc = make_asset_value_adjustment(asset = asset_doc.name, current_asset_value = current_value, new_asset_value = 50000.0) adj_doc.submit() expected_gle = ( ("_Test Accumulated Depreciations - _TC", 0.0, 50000.0), ("_Test Depreciations - _TC", 50000.0, 0.0) ) gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no = %s order by account""", adj_doc.journal_entry) self.assertEqual(gle, expected_gle)
def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True): deducted_dates = [] i = 0 while i < 12: slip = frappe.get_doc({"doctype": "Salary Slip", "employee": employee, "salary_structure": salary_structure, "frequency": "Monthly"}) if i == 0: posting_date = add_days(payroll_period.start_date, 25) else: posting_date = add_months(posting_date, 1) if i == 11: slip.deduct_tax_for_unsubmitted_tax_exemption_proof = 1 slip.deduct_tax_for_unclaimed_employee_benefits = 1 if deduct_random and not random.randint(0, 2): slip.deduct_tax_for_unsubmitted_tax_exemption_proof = 1 deducted_dates.append(posting_date) slip.posting_date = posting_date slip.start_date = get_first_day(posting_date) slip.end_date = get_last_day(posting_date) doc = make_salary_slip(salary_structure, slip, employee) doc.submit() i += 1 return deducted_dates
def _test(i): self.assertEquals(i+1, frappe.db.sql("""select count(*) from `tabSales Invoice` where recurring_id=%s and docstatus=1""", base_si.recurring_id)[0][0]) next_date = get_next_date(base_si.posting_date, no_of_months, base_si.repeat_on_day_of_month) manage_recurring_invoices(next_date=next_date, commit=False) recurred_invoices = frappe.db.sql("""select name from `tabSales Invoice` where recurring_id=%s and docstatus=1 order by name desc""", base_si.recurring_id) self.assertEquals(i+2, len(recurred_invoices)) new_si = frappe.get_doc("Sales Invoice", recurred_invoices[0][0]) for fieldname in ["convert_into_recurring_invoice", "recurring_type", "repeat_on_day_of_month", "notification_email_address"]: self.assertEquals(base_si.get(fieldname), new_si.get(fieldname)) self.assertEquals(new_si.posting_date, unicode(next_date)) self.assertEquals(new_si.invoice_period_from_date, unicode(add_months(base_si.invoice_period_from_date, no_of_months))) if first_and_last_day: self.assertEquals(new_si.invoice_period_to_date, unicode(get_last_day(add_months(base_si.invoice_period_to_date, no_of_months)))) else: self.assertEquals(new_si.invoice_period_to_date, unicode(add_months(base_si.invoice_period_to_date, no_of_months))) return new_si
def test_current_asset_value(self): pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location") asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_doc = frappe.get_doc('Asset', asset_name) month_end_date = get_last_day(nowdate()) purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) asset_doc.available_for_use_date = purchase_date asset_doc.purchase_date = purchase_date asset_doc.calculate_depreciation = 1 asset_doc.append("finance_books", { "expected_value_after_useful_life": 200, "depreciation_method": "Straight Line", "total_number_of_depreciations": 3, "frequency_of_depreciation": 10, "depreciation_start_date": month_end_date }) asset_doc.submit() current_value = get_current_asset_value(asset_doc.name) self.assertEqual(current_value, 100000.0)
def make_dep_schedule(doc, base_dep_date, exp_val_aft_life, dep_freq, tot_dep): dont_make_sch = 0 fy_doc = get_fy_doc(doc) diff_pd_npd = relativedelta.relativedelta(add_days(base_dep_date,1), getdate(doc.purchase_date)) diff_months = diff_pd_npd.years*12 + diff_pd_npd.months diff_days = date_diff(add_days(doc.next_depreciation_date,1), doc.purchase_date) fy_days = date_diff(fy_doc.year_end_date, fy_doc.year_start_date) middle_purchase_factor = flt(diff_days)/flt(fy_days) if tot_dep == cint(doc.number_of_depreciations_booked): doc.opening_accumulated_depreciation = (doc.gross_purchase_amount - exp_val_aft_life) doc.schedules = [] dont_make_sch = 1 else: if doc.opening_accumulated_depreciation == (doc.gross_purchase_amount - exp_val_aft_life): doc.number_of_depreciations_booked = tot_dep doc.schedules = [] dont_make_sch = 1 if doc.depreciation_method != 'Manual': doc.schedules = [] if dont_make_sch != 1: if not doc.get("schedules") and doc.next_depreciation_date: value_after_depreciation = doc.gross_purchase_amount - doc.opening_accumulated_depreciation if diff_months < dep_freq: number_of_pending_depreciations = cint(tot_dep) - \ cint(doc.number_of_depreciations_booked) + 1 else: number_of_pending_depreciations = cint(tot_dep) - \ cint(doc.number_of_depreciations_booked) if number_of_pending_depreciations: for n in range(number_of_pending_depreciations): schedule_date = get_last_day(add_months(doc.next_depreciation_date, n * cint(dep_freq))) if diff_months < dep_freq and n==0 and \ cint(doc.number_of_depreciations_booked) == 0: depreciation_amount = get_depreciation_amount(doc, \ value_after_depreciation, middle_purchase_factor) else: depreciation_amount = get_depreciation_amount(doc, \ value_after_depreciation, 1) value_after_depreciation = value_after_depreciation - flt(depreciation_amount) doc.append("schedules", { "schedule_date": schedule_date, "depreciation_amount": depreciation_amount }) #frappe.throw(str(number_of_pending_depreciations)) accumulated_depreciation = flt(doc.opening_accumulated_depreciation) value_after_depreciation = flt(doc.value_after_depreciation) for i, d in enumerate(doc.get("schedules")): depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) if i==len(doc.get("schedules"))-1 and doc.depreciation_method == "Straight Line": depreciation_amount = flt((doc.gross_purchase_amount) - flt(accumulated_depreciation) - flt(exp_val_aft_life), d.precision("depreciation_amount")) d.depreciation_amount = depreciation_amount accumulated_depreciation += d.depreciation_amount d.accumulated_depreciation_amount = flt(accumulated_depreciation, \ d.precision("accumulated_depreciation_amount"))
def work(): frappe.set_user(frappe.db.get_global('demo_hr_user')) year, month = frappe.flags.current_date.strftime("%Y-%m").split("-") mark_attendance() make_leave_application() # process payroll if not frappe.db.sql('select name from `tabSalary Slip` where month(adddate(start_date, interval 1 month))=month(curdate())'): # process payroll for previous month process_payroll = frappe.get_doc("Process Payroll", "Process Payroll") process_payroll.company = frappe.flags.company process_payroll.payroll_frequency = 'Monthly' # select a posting date from the previous month process_payroll.posting_date = get_last_day(getdate(frappe.flags.current_date) - datetime.timedelta(days=10)) process_payroll.payment_account = frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name") process_payroll.set_start_end_dates() # based on frequency process_payroll.salary_slip_based_on_timesheet = 0 process_payroll.create_salary_slips() process_payroll.submit_salary_slips() process_payroll.make_journal_entry(reference_date=frappe.flags.current_date, reference_number=random_string(10)) process_payroll.salary_slip_based_on_timesheet = 1 process_payroll.create_salary_slips() process_payroll.submit_salary_slips() process_payroll.make_journal_entry(reference_date=frappe.flags.current_date, reference_number=random_string(10)) if frappe.db.get_global('demo_hr_user'): make_timesheet_records() #expense claim expense_claim = frappe.new_doc("Expense Claim") expense_claim.extend('expenses', get_expenses()) expense_claim.employee = get_random("Employee") expense_claim.company = frappe.flags.company expense_claim.posting_date = frappe.flags.current_date expense_claim.exp_approver = filter((lambda x: x[0] != 'Administrator'), get_expense_approver(None, '', None, 0, 20, None))[0][0] expense_claim.insert() rand = random.random() if rand < 0.4: expense_claim.approval_status = "Approved" update_sanctioned_amount(expense_claim) expense_claim.submit() if random.randint(0, 1): #make journal entry against expense claim je = frappe.get_doc(make_bank_entry(expense_claim.name)) je.posting_date = frappe.flags.current_date je.cheque_no = random_string(10) je.cheque_date = frappe.flags.current_date je.flags.ignore_permissions = 1 je.submit() elif rand < 0.2: expense_claim.approval_status = "Rejected" expense_claim.submit()
def get_period_list(fiscal_year, periodicity): """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" fy_start_end_date = frappe.db.get_value("Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) if not fy_start_end_date: frappe.throw(_("Fiscal Year {0} not found.").format(fiscal_year)) # start with first day, so as to avoid year to_dates like 2-April if ever they occur] year_start_date = get_first_day(getdate(fy_start_end_date[0])) year_end_date = getdate(fy_start_end_date[1]) if periodicity == "Yearly": period_list = [frappe._dict({"from_date": year_start_date, "to_date": year_end_date, "key": fiscal_year, "label": fiscal_year})] else: months_to_add = { "Half-Yearly": 6, "Quarterly": 3, "Monthly": 1 }[periodicity] period_list = [] start_date = year_start_date for i in xrange(12 / months_to_add): period = frappe._dict({ "from_date": start_date }) to_date = add_months(start_date, months_to_add) start_date = to_date if to_date == get_first_day(to_date): # if to_date is the first day, get the last day of previous month to_date = add_days(to_date, -1) else: # to_date should be the last day of the new to_date's month to_date = get_last_day(to_date) if to_date <= year_end_date: # the normal case period.to_date = to_date else: # if a fiscal year ends before a 12 month period period.to_date = year_end_date period_list.append(period) if period.to_date == year_end_date: break # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() if periodicity == "Monthly": label = formatdate(opts["to_date"], "MMM YYYY") else: label = get_label(periodicity, opts["from_date"], opts["to_date"]) opts.update({ "key": key.replace(" ", "_").replace("-", "_"), "label": label, "year_start_date": year_start_date, "year_end_date": year_end_date }) return period_list
def test_recurring_invoice(self): from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate from erpnext.accounts.utils import get_fiscal_year today = nowdate() base_si = frappe.copy_doc(test_records[0]) base_si.update({ "convert_into_recurring_invoice": 1, "recurring_type": "Monthly", "notification_email_address": "[email protected], [email protected], [email protected]", "repeat_on_day_of_month": getdate(today).day, "posting_date": today, "fiscal_year": get_fiscal_year(today)[0], "invoice_period_from_date": get_first_day(today), "invoice_period_to_date": get_last_day(today) }) # monthly si1 = frappe.copy_doc(base_si) si1.insert() si1.submit() self._test_recurring_invoice(si1, True) # monthly without a first and last day period si2 = frappe.copy_doc(base_si) si2.update({ "invoice_period_from_date": today, "invoice_period_to_date": add_to_date(today, days=30) }) si2.insert() si2.submit() self._test_recurring_invoice(si2, False) # quarterly si3 = frappe.copy_doc(base_si) si3.update({ "recurring_type": "Quarterly", "invoice_period_from_date": get_first_day(today), "invoice_period_to_date": get_last_day(add_to_date(today, months=3)) }) si3.insert() si3.submit() self._test_recurring_invoice(si3, True) # quarterly without a first and last day period si4 = frappe.copy_doc(base_si) si4.update({ "recurring_type": "Quarterly", "invoice_period_from_date": today, "invoice_period_to_date": add_to_date(today, months=3) }) si4.insert() si4.submit() self._test_recurring_invoice(si4, False) # yearly si5 = frappe.copy_doc(base_si) si5.update({ "recurring_type": "Yearly", "invoice_period_from_date": get_first_day(today), "invoice_period_to_date": get_last_day(add_to_date(today, years=1)) }) si5.insert() si5.submit() self._test_recurring_invoice(si5, True) # yearly without a first and last day period si6 = frappe.copy_doc(base_si) si6.update({ "recurring_type": "Yearly", "invoice_period_from_date": today, "invoice_period_to_date": add_to_date(today, years=1) }) si6.insert() si6.submit() self._test_recurring_invoice(si6, False) # change posting date but keep recuring day to be today si7 = frappe.copy_doc(base_si) si7.update({ "posting_date": add_to_date(today, days=-1) }) si7.insert() si7.submit() # setting so that _test function works si7.posting_date = today self._test_recurring_invoice(si7, True)
def test_recurring_document(obj, test_records): from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate, add_days from erpnext.accounts.utils import get_fiscal_year frappe.db.set_value("Print Settings", "Print Settings", "send_print_as_pdf", 1) today = nowdate() base_doc = frappe.copy_doc(test_records[0]) base_doc.update({ "is_recurring": 1, "recurring_type": "Monthly", "notification_email_address": "[email protected], [email protected], [email protected]", "repeat_on_day_of_month": getdate(today).day, "due_date": None, "fiscal_year": get_fiscal_year(today)[0], "from_date": get_first_day(today), "to_date": get_last_day(today) }) if base_doc.doctype == "Sales Order": base_doc.update({ "transaction_date": today, "delivery_date": add_days(today, 15) }) elif base_doc.doctype == "Sales Invoice": base_doc.update({ "posting_date": today }) if base_doc.doctype == "Sales Order": date_field = "transaction_date" elif base_doc.doctype == "Sales Invoice": date_field = "posting_date" # monthly doc1 = frappe.copy_doc(base_doc) doc1.insert() doc1.submit() _test_recurring_document(obj, doc1, date_field, True) # monthly without a first and last day period doc2 = frappe.copy_doc(base_doc) doc2.update({ "from_date": today, "to_date": add_to_date(today, days=30) }) doc2.insert() doc2.submit() _test_recurring_document(obj, doc2, date_field, False) # quarterly doc3 = frappe.copy_doc(base_doc) doc3.update({ "recurring_type": "Quarterly", "from_date": get_first_day(today), "to_date": get_last_day(add_to_date(today, months=3)) }) doc3.insert() doc3.submit() _test_recurring_document(obj, doc3, date_field, True) # quarterly without a first and last day period doc4 = frappe.copy_doc(base_doc) doc4.update({ "recurring_type": "Quarterly", "from_date": today, "to_date": add_to_date(today, months=3) }) doc4.insert() doc4.submit() _test_recurring_document(obj, doc4, date_field, False) # yearly doc5 = frappe.copy_doc(base_doc) doc5.update({ "recurring_type": "Yearly", "from_date": get_first_day(today), "to_date": get_last_day(add_to_date(today, years=1)) }) doc5.insert() doc5.submit() _test_recurring_document(obj, doc5, date_field, True) # yearly without a first and last day period doc6 = frappe.copy_doc(base_doc) doc6.update({ "recurring_type": "Yearly", "from_date": today, "to_date": add_to_date(today, years=1) }) doc6.insert() doc6.submit() _test_recurring_document(obj, doc6, date_field, False) # change date field but keep recurring day to be today doc7 = frappe.copy_doc(base_doc) doc7.update({ date_field: today, }) doc7.insert() doc7.submit() # setting so that _test function works # doc7.set(date_field, today) _test_recurring_document(obj, doc7, date_field, True)
def get_period_list(fiscal_year, periodicity, from_beginning=False): """Get a list of dict {"to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" fy_start_end_date = frappe.db.get_value("Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) if not fy_start_end_date: frappe.throw(_("Fiscal Year {0} not found.").format(fiscal_year)) start_date = getdate(fy_start_end_date[0]) end_date = getdate(fy_start_end_date[1]) if periodicity == "Yearly": period_list = [_dict({"to_date": end_date, "key": fiscal_year, "label": fiscal_year})] else: months_to_add = { "Half-yearly": 6, "Quarterly": 3, "Monthly": 1 }[periodicity] period_list = [] # start with first day, so as to avoid year to_dates like 2-April if ever they occur to_date = get_first_day(start_date) for i in xrange(12 / months_to_add): to_date = add_months(to_date, months_to_add) if to_date == get_first_day(to_date): # if to_date is the first day, get the last day of previous month to_date = add_days(to_date, -1) else: # to_date should be the last day of the new to_date's month to_date = get_last_day(to_date) if to_date <= end_date: # the normal case period_list.append(_dict({ "to_date": to_date })) # if it ends before a full year if to_date == end_date: break else: # if a fiscal year ends before a 12 month period period_list.append(_dict({ "to_date": end_date })) break # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() label = formatdate(opts["to_date"], "MMM YYYY") opts.update({ "key": key.replace(" ", "_").replace("-", "_"), "label": label, "year_start_date": start_date, "year_end_date": end_date }) if from_beginning: # set start date as None for all fiscal periods, used in case of Balance Sheet opts["from_date"] = None else: opts["from_date"] = start_date return period_list
def calculate_depreciation_date(): return get_last_day(nowdate());