', {
- therapy: y[0],
- name: y[1], encounter: y[2], practitioner: y[3], date: y[4],
- department: y[6] ? y[6] : '', therapy_plan: y[5]
- })).appendTo(html_field);
-
- row.find("a").click(function() {
- frm.doc.therapy_type = $(this).attr("data-therapy");
- frm.doc.practitioner = $(this).attr("data-practitioner");
- frm.doc.department = $(this).attr("data-department");
- frm.doc.therapy_plan = $(this).attr("data-therapy-plan");
- frm.refresh_field("therapy_type");
- frm.refresh_field("practitioner");
- frm.refresh_field("department");
- frm.refresh_field("therapy-plan");
- frappe.db.get_value('Therapy Type', frm.doc.therapy_type, 'default_duration', (r) => {
- if (r.default_duration) {
- frm.set_value('duration', r.default_duration)
- }
- });
- d.hide();
- return false;
- });
- });
- d.show();
-};
-
-let create_vital_signs = function(frm) {
- if (!frm.doc.patient) {
- frappe.throw(__('Please select patient'));
- }
- frappe.route_options = {
- 'patient': frm.doc.patient,
- 'appointment': frm.doc.name,
- 'company': frm.doc.company
- };
- frappe.new_doc('Vital Signs');
-};
-
-let update_status = function(frm, status) {
- let doc = frm.doc;
- frappe.confirm(__('Are you sure you want to cancel this appointment?'),
- function() {
- frappe.call({
- method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status',
- args: { appointment_id: doc.name, status: status },
- callback: function(data) {
- if (!data.exc) {
- frm.reload_doc();
- }
- }
- });
- }
- );
-};
-
-let calculate_age = function(birth) {
- let ageMS = Date.parse(Date()) - Date.parse(birth);
- let age = new Date();
- age.setTime(ageMS);
- let years = age.getFullYear() - 1970;
- return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`;
-};
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
deleted file mode 100644
index 28d3a6dadf6..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
+++ /dev/null
@@ -1,403 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "allow_import": 1,
- "autoname": "naming_series:",
- "beta": 1,
- "creation": "2017-05-04 11:52:40.941507",
- "doctype": "DocType",
- "document_type": "Document",
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "title",
- "status",
- "patient",
- "patient_name",
- "patient_sex",
- "patient_age",
- "inpatient_record",
- "column_break_1",
- "company",
- "practitioner",
- "practitioner_name",
- "department",
- "service_unit",
- "section_break_12",
- "appointment_type",
- "duration",
- "procedure_template",
- "get_procedure_from_encounter",
- "procedure_prescription",
- "therapy_plan",
- "therapy_type",
- "get_prescribed_therapies",
- "column_break_17",
- "appointment_date",
- "appointment_time",
- "appointment_datetime",
- "section_break_16",
- "mode_of_payment",
- "billing_item",
- "invoiced",
- "column_break_2",
- "paid_amount",
- "ref_sales_invoice",
- "section_break_3",
- "referring_practitioner",
- "reminded",
- "column_break_36",
- "notes"
- ],
- "fields": [
- {
- "fetch_from": "patient.inpatient_record",
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "label": "Inpatient Record",
- "options": "Inpatient Record",
- "read_only": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "appointment_type",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Appointment Type",
- "options": "Appointment Type",
- "set_only_once": 1
- },
- {
- "fetch_from": "appointment_type.default_duration",
- "fieldname": "duration",
- "fieldtype": "Int",
- "in_filter": 1,
- "label": "Duration (In Minutes)",
- "set_only_once": 1
- },
- {
- "fieldname": "column_break_1",
- "fieldtype": "Column Break",
- "read_only": 1
- },
- {
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "status",
- "fieldtype": "Select",
- "in_filter": 1,
- "in_list_view": 1,
- "label": "Status",
- "options": "\nScheduled\nOpen\nClosed\nCancelled",
- "read_only": 1,
- "search_index": 1
- },
- {
- "depends_on": "eval:doc.patient;",
- "fieldname": "procedure_template",
- "fieldtype": "Link",
- "label": "Clinical Procedure Template",
- "options": "Clinical Procedure Template",
- "set_only_once": 1
- },
- {
- "depends_on": "eval:doc.__islocal && doc.patient",
- "fieldname": "get_procedure_from_encounter",
- "fieldtype": "Button",
- "label": "Get Prescribed Clinical Procedures"
- },
- {
- "fieldname": "procedure_prescription",
- "fieldtype": "Link",
- "hidden": 1,
- "label": "Procedure Prescription",
- "no_copy": 1,
- "options": "Procedure Prescription",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "service_unit",
- "fieldtype": "Link",
- "label": "Service Unit",
- "options": "Healthcare Service Unit",
- "read_only": 1
- },
- {
- "depends_on": "eval:doc.practitioner;",
- "fieldname": "section_break_12",
- "fieldtype": "Section Break",
- "label": "Appointment Details"
- },
- {
- "fieldname": "practitioner",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Healthcare Practitioner",
- "options": "Healthcare Practitioner",
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 1
- },
- {
- "fetch_from": "practitioner.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Department",
- "options": "Medical Department",
- "search_index": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "column_break_17",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "appointment_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Date",
- "read_only": 1,
- "reqd": 1,
- "search_index": 1
- },
- {
- "fieldname": "appointment_time",
- "fieldtype": "Time",
- "in_list_view": 1,
- "label": "Time",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "section_break_16",
- "fieldtype": "Section Break",
- "label": "Payments"
- },
- {
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- },
- {
- "fetch_from": "patient.sex",
- "fieldname": "patient_sex",
- "fieldtype": "Link",
- "label": "Gender",
- "no_copy": 1,
- "options": "Gender",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1
- },
- {
- "fieldname": "patient_age",
- "fieldtype": "Data",
- "label": "Patient Age",
- "read_only": 1
- },
- {
- "fieldname": "appointment_datetime",
- "fieldtype": "Datetime",
- "hidden": 1,
- "label": "Appointment Datetime",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1,
- "search_index": 1
- },
- {
- "fieldname": "mode_of_payment",
- "fieldtype": "Link",
- "label": "Mode of Payment",
- "options": "Mode of Payment",
- "read_only_depends_on": "invoiced"
- },
- {
- "fieldname": "paid_amount",
- "fieldtype": "Currency",
- "label": "Paid Amount",
- "read_only_depends_on": "invoiced"
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "label": "Invoiced",
- "read_only": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Company",
- "no_copy": 1,
- "options": "Company",
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "collapsible": 1,
- "fieldname": "section_break_3",
- "fieldtype": "Section Break",
- "label": "More Info"
- },
- {
- "fieldname": "notes",
- "fieldtype": "Small Text",
- "ignore_xss_filter": 1,
- "label": "Notes"
- },
- {
- "fieldname": "referring_practitioner",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Referring Practitioner",
- "options": "Healthcare Practitioner"
- },
- {
- "default": "0",
- "fieldname": "reminded",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Reminded",
- "print_hide": 1,
- "report_hide": 1
- },
- {
- "depends_on": "eval:doc.patient && doc.therapy_plan;",
- "fieldname": "therapy_type",
- "fieldtype": "Link",
- "label": "Therapy",
- "options": "Therapy Type",
- "set_only_once": 1
- },
- {
- "depends_on": "eval:doc.patient && doc.therapy_plan && doc.__islocal;",
- "fieldname": "get_prescribed_therapies",
- "fieldtype": "Button",
- "label": "Get Prescribed Therapies"
- },
- {
- "depends_on": "eval: doc.patient;",
- "fieldname": "therapy_plan",
- "fieldtype": "Link",
- "label": "Therapy Plan",
- "options": "Therapy Plan",
- "set_only_once": 1
- },
- {
- "fieldname": "ref_sales_invoice",
- "fieldtype": "Link",
- "label": "Reference Sales Invoice",
- "options": "Sales Invoice",
- "read_only": 1
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "HLC-APP-.YYYY.-",
- "set_only_once": 1
- },
- {
- "fieldname": "billing_item",
- "fieldtype": "Link",
- "label": "Billing Item",
- "options": "Item",
- "read_only": 1
- },
- {
- "fieldname": "column_break_36",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Title",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fetch_from": "practitioner.practitioner_name",
- "fieldname": "practitioner_name",
- "fieldtype": "Data",
- "label": "Practitioner Name",
- "read_only": 1
- }
- ],
- "links": [],
- "modified": "2021-08-30 09:00:41.329387",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Appointment",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Nursing User",
- "share": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient, practitioner, department, appointment_date, appointment_time",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 1
-}
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
deleted file mode 100755
index dcbcda09d81..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ /dev/null
@@ -1,559 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import datetime
-import json
-
-import frappe
-from frappe import _
-from frappe.core.doctype.sms_settings.sms_settings import send_sms
-from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, get_link_to_form, get_time, getdate
-
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
- get_income_account,
- get_receivable_account,
-)
-from erpnext.healthcare.utils import (
- check_fee_validity,
- get_service_item_and_practitioner_charge,
- manage_fee_validity,
-)
-from erpnext.hr.doctype.employee.employee import is_holiday
-
-
-class MaximumCapacityError(frappe.ValidationError):
- pass
-class OverlapError(frappe.ValidationError):
- pass
-
-class PatientAppointment(Document):
- def validate(self):
- self.validate_overlaps()
- self.validate_service_unit()
- self.set_appointment_datetime()
- self.validate_customer_created()
- self.set_status()
- self.set_title()
-
- def after_insert(self):
- self.update_prescription_details()
- self.set_payment_details()
- invoice_appointment(self)
- self.update_fee_validity()
- send_confirmation_msg(self)
-
- def set_title(self):
- self.title = _('{0} with {1}').format(self.patient_name or self.patient,
- self.practitioner_name or self.practitioner)
-
- def set_status(self):
- today = getdate()
- appointment_date = getdate(self.appointment_date)
-
- # If appointment is created for today set status as Open else Scheduled
- if appointment_date == today:
- self.status = 'Open'
- elif appointment_date > today:
- self.status = 'Scheduled'
-
- def validate_overlaps(self):
- end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \
- + datetime.timedelta(minutes=flt(self.duration))
-
- # all appointments for both patient and practitioner overlapping the duration of this appointment
- overlapping_appointments = frappe.db.sql("""
- SELECT
- name, practitioner, patient, appointment_time, duration, service_unit
- FROM
- `tabPatient Appointment`
- WHERE
- appointment_date=%(appointment_date)s AND name!=%(name)s AND status NOT IN ("Closed", "Cancelled") AND
- (practitioner=%(practitioner)s OR patient=%(patient)s) AND
- ((appointment_time<%(appointment_time)s AND appointment_time + INTERVAL duration MINUTE>%(appointment_time)s) OR
- (appointment_time>%(appointment_time)s AND appointment_time<%(end_time)s) OR
- (appointment_time=%(appointment_time)s))
- """,
- {
- 'appointment_date': self.appointment_date,
- 'name': self.name,
- 'practitioner': self.practitioner,
- 'patient': self.patient,
- 'appointment_time': self.appointment_time,
- 'end_time':end_time.time()
- },
- as_dict = True
- )
-
- if not overlapping_appointments:
- return # No overlaps, nothing to validate!
-
- if self.service_unit: # validate service unit capacity if overlap enabled
- allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', self.service_unit,
- ['overlap_appointments', 'service_unit_capacity'])
- if allow_overlap:
- service_unit_appointments = list(filter(lambda appointment: appointment['service_unit'] == self.service_unit and
- appointment['patient'] != self.patient, overlapping_appointments)) # if same patient already booked, it should be an overlap
- if len(service_unit_appointments) >= (service_unit_capacity or 1):
- frappe.throw(_("Not allowed, {} cannot exceed maximum capacity {}")
- .format(frappe.bold(self.service_unit), frappe.bold(service_unit_capacity or 1)), MaximumCapacityError)
- else: # service_unit_appointments within capacity, remove from overlapping_appointments
- overlapping_appointments = [appointment for appointment in overlapping_appointments if appointment not in service_unit_appointments]
-
- if overlapping_appointments:
- frappe.throw(_("Not allowed, cannot overlap appointment {}")
- .format(frappe.bold(', '.join([appointment['name'] for appointment in overlapping_appointments]))), OverlapError)
-
-
- def validate_service_unit(self):
- if self.inpatient_record and self.service_unit:
- from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import (
- get_current_healthcare_service_unit,
- )
-
- is_inpatient_occupancy_unit = frappe.db.get_value('Healthcare Service Unit', self.service_unit,
- 'inpatient_occupancy')
- service_unit = get_current_healthcare_service_unit(self.inpatient_record)
- if is_inpatient_occupancy_unit and service_unit != self.service_unit:
- msg = _('Patient {0} is not admitted in the service unit {1}').format(frappe.bold(self.patient), frappe.bold(self.service_unit)) + '
'
- msg += _('Appointment for service units with Inpatient Occupancy can only be created against the unit where patient has been admitted.')
- frappe.throw(msg, title=_('Invalid Healthcare Service Unit'))
-
-
- def set_appointment_datetime(self):
- self.appointment_datetime = "%s %s" % (self.appointment_date, self.appointment_time or "00:00:00")
-
- def set_payment_details(self):
- if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'):
- details = get_service_item_and_practitioner_charge(self)
- self.db_set('billing_item', details.get('service_item'))
- if not self.paid_amount:
- self.db_set('paid_amount', details.get('practitioner_charge'))
-
- def validate_customer_created(self):
- if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'):
- if not frappe.db.get_value('Patient', self.patient, 'customer'):
- msg = _("Please set a Customer linked to the Patient")
- msg += "
{0} ".format(self.patient)
- frappe.throw(msg, title=_('Customer Not Found'))
-
- def update_prescription_details(self):
- if self.procedure_prescription:
- frappe.db.set_value('Procedure Prescription', self.procedure_prescription, 'appointment_booked', 1)
- if self.procedure_template:
- comments = frappe.db.get_value('Procedure Prescription', self.procedure_prescription, 'comments')
- if comments:
- frappe.db.set_value('Patient Appointment', self.name, 'notes', comments)
-
- def update_fee_validity(self):
- if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
- return
-
- fee_validity = manage_fee_validity(self)
- if fee_validity:
- frappe.msgprint(_('{0}: {1} has fee validity till {2}').format(self.patient,
- frappe.bold(self.patient_name), fee_validity.valid_till))
-
- @frappe.whitelist()
- def get_therapy_types(self):
- if not self.therapy_plan:
- return
-
- therapy_types = []
- doc = frappe.get_doc('Therapy Plan', self.therapy_plan)
- for entry in doc.therapy_plan_details:
- therapy_types.append(entry.therapy_type)
-
- return therapy_types
-
-
-@frappe.whitelist()
-def check_payment_fields_reqd(patient):
- automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing')
- free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups')
- if automate_invoicing:
- if free_follow_ups:
- fee_validity = frappe.db.exists('Fee Validity', {'patient': patient, 'status': 'Pending'})
- if fee_validity:
- return {'fee_validity': fee_validity}
- return True
- return False
-
-def invoice_appointment(appointment_doc):
- automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing')
- appointment_invoiced = frappe.db.get_value('Patient Appointment', appointment_doc.name, 'invoiced')
- enable_free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups')
- if enable_free_follow_ups:
- fee_validity = check_fee_validity(appointment_doc)
- if fee_validity and fee_validity.status == 'Completed':
- fee_validity = None
- elif not fee_validity:
- if frappe.db.exists('Fee Validity Reference', {'appointment': appointment_doc.name}):
- return
- else:
- fee_validity = None
-
- if automate_invoicing and not appointment_invoiced and not fee_validity:
- create_sales_invoice(appointment_doc)
-
-
-def create_sales_invoice(appointment_doc):
- sales_invoice = frappe.new_doc('Sales Invoice')
- sales_invoice.patient = appointment_doc.patient
- sales_invoice.customer = frappe.get_value('Patient', appointment_doc.patient, 'customer')
- sales_invoice.appointment = appointment_doc.name
- sales_invoice.due_date = getdate()
- sales_invoice.company = appointment_doc.company
- sales_invoice.debit_to = get_receivable_account(appointment_doc.company)
-
- item = sales_invoice.append('items', {})
- item = get_appointment_item(appointment_doc, item)
-
- # Add payments if payment details are supplied else proceed to create invoice as Unpaid
- if appointment_doc.mode_of_payment and appointment_doc.paid_amount:
- sales_invoice.is_pos = 1
- payment = sales_invoice.append('payments', {})
- payment.mode_of_payment = appointment_doc.mode_of_payment
- payment.amount = appointment_doc.paid_amount
-
- sales_invoice.set_missing_values(for_validate=True)
- sales_invoice.flags.ignore_mandatory = True
- sales_invoice.save(ignore_permissions=True)
- sales_invoice.submit()
- frappe.msgprint(_('Sales Invoice {0} created').format(sales_invoice.name), alert=True)
- frappe.db.set_value('Patient Appointment', appointment_doc.name, {
- 'invoiced': 1,
- 'ref_sales_invoice': sales_invoice.name
- })
-
-
-def check_is_new_patient(patient, name=None):
- filters = {'patient': patient, 'status': ('!=','Cancelled')}
- if name:
- filters['name'] = ('!=', name)
-
- has_previous_appointment = frappe.db.exists('Patient Appointment', filters)
- return not has_previous_appointment
-
-
-def get_appointment_item(appointment_doc, item):
- details = get_service_item_and_practitioner_charge(appointment_doc)
- charge = appointment_doc.paid_amount or details.get('practitioner_charge')
- item.item_code = details.get('service_item')
- item.description = _('Consulting Charges: {0}').format(appointment_doc.practitioner)
- item.income_account = get_income_account(appointment_doc.practitioner, appointment_doc.company)
- item.cost_center = frappe.get_cached_value('Company', appointment_doc.company, 'cost_center')
- item.rate = charge
- item.amount = charge
- item.qty = 1
- item.reference_dt = 'Patient Appointment'
- item.reference_dn = appointment_doc.name
- return item
-
-
-def cancel_appointment(appointment_id):
- appointment = frappe.get_doc('Patient Appointment', appointment_id)
- if appointment.invoiced:
- sales_invoice = check_sales_invoice_exists(appointment)
- if sales_invoice and cancel_sales_invoice(sales_invoice):
- msg = _('Appointment {0} and Sales Invoice {1} cancelled').format(appointment.name, sales_invoice.name)
- else:
- msg = _('Appointment Cancelled. Please review and cancel the invoice {0}').format(sales_invoice.name)
- else:
- fee_validity = manage_fee_validity(appointment)
- msg = _('Appointment Cancelled.')
- if fee_validity:
- msg += _('Fee Validity {0} updated.').format(fee_validity.name)
-
- frappe.msgprint(msg)
-
-
-def cancel_sales_invoice(sales_invoice):
- if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'):
- if len(sales_invoice.items) == 1:
- sales_invoice.cancel()
- return True
- return False
-
-
-def check_sales_invoice_exists(appointment):
- sales_invoice = frappe.db.get_value('Sales Invoice Item', {
- 'reference_dt': 'Patient Appointment',
- 'reference_dn': appointment.name
- }, 'parent')
-
- if sales_invoice:
- sales_invoice = frappe.get_doc('Sales Invoice', sales_invoice)
- return sales_invoice
- return False
-
-
-@frappe.whitelist()
-def get_availability_data(date, practitioner):
- """
- Get availability data of 'practitioner' on 'date'
- :param date: Date to check in schedule
- :param practitioner: Name of the practitioner
- :return: dict containing a list of available slots, list of appointments and time of appointments
- """
-
- date = getdate(date)
- weekday = date.strftime('%A')
-
- practitioner_doc = frappe.get_doc('Healthcare Practitioner', practitioner)
-
- check_employee_wise_availability(date, practitioner_doc)
-
- if practitioner_doc.practitioner_schedules:
- slot_details = get_available_slots(practitioner_doc, date)
- else:
- frappe.throw(_('{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master').format(
- practitioner), title=_('Practitioner Schedule Not Found'))
-
-
- if not slot_details:
- # TODO: return available slots in nearby dates
- frappe.throw(_('Healthcare Practitioner not available on {0}').format(weekday), title=_('Not Available'))
-
- return {'slot_details': slot_details}
-
-
-def check_employee_wise_availability(date, practitioner_doc):
- employee = None
- if practitioner_doc.employee:
- employee = practitioner_doc.employee
- elif practitioner_doc.user_id:
- employee = frappe.db.get_value('Employee', {'user_id': practitioner_doc.user_id}, 'name')
-
- if employee:
- # check holiday
- if is_holiday(employee, date):
- frappe.throw(_('{0} is a holiday'.format(date)), title=_('Not Available'))
-
- # check leave status
- leave_record = frappe.db.sql("""select half_day from `tabLeave Application`
- where employee = %s and %s between from_date and to_date
- and docstatus = 1""", (employee, date), as_dict=True)
- if leave_record:
- if leave_record[0].half_day:
- frappe.throw(_('{0} is on a Half day Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available'))
- else:
- frappe.throw(_('{0} is on Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available'))
-
-
-def get_available_slots(practitioner_doc, date):
- available_slots = slot_details = []
- weekday = date.strftime('%A')
- practitioner = practitioner_doc.name
-
- for schedule_entry in practitioner_doc.practitioner_schedules:
- validate_practitioner_schedules(schedule_entry, practitioner)
- practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule_entry.schedule)
-
- if practitioner_schedule:
- available_slots = []
- for time_slot in practitioner_schedule.time_slots:
- if weekday == time_slot.day:
- available_slots.append(time_slot)
-
- if available_slots:
- appointments = []
- allow_overlap = 0
- service_unit_capacity = 0
- # fetch all appointments to practitioner by service unit
- filters = {
- 'practitioner': practitioner,
- 'service_unit': schedule_entry.service_unit,
- 'appointment_date': date,
- 'status': ['not in',['Cancelled']]
- }
-
- if schedule_entry.service_unit:
- slot_name = f'{schedule_entry.schedule}'
- allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', schedule_entry.service_unit, ['overlap_appointments', 'service_unit_capacity'])
- if not allow_overlap:
- # fetch all appointments to service unit
- filters.pop('practitioner')
- else:
- slot_name = schedule_entry.schedule
- # fetch all appointments to practitioner without service unit
- filters['practitioner'] = practitioner
- filters.pop('service_unit')
-
- appointments = frappe.get_all(
- 'Patient Appointment',
- filters=filters,
- fields=['name', 'appointment_time', 'duration', 'status'])
-
- slot_details.append({'slot_name': slot_name, 'service_unit': schedule_entry.service_unit, 'avail_slot': available_slots,
- 'appointments': appointments, 'allow_overlap': allow_overlap, 'service_unit_capacity': service_unit_capacity})
-
- return slot_details
-
-
-def validate_practitioner_schedules(schedule_entry, practitioner):
- if schedule_entry.schedule:
- if not schedule_entry.service_unit:
- frappe.throw(_('Practitioner {0} does not have a Service Unit set against the Practitioner Schedule {1}.').format(
- get_link_to_form('Healthcare Practitioner', practitioner), frappe.bold(schedule_entry.schedule)),
- title=_('Service Unit Not Found'))
-
- else:
- frappe.throw(_('Practitioner {0} does not have a Practitioner Schedule assigned.').format(
- get_link_to_form('Healthcare Practitioner', practitioner)),
- title=_('Practitioner Schedule Not Found'))
-
-
-@frappe.whitelist()
-def update_status(appointment_id, status):
- frappe.db.set_value('Patient Appointment', appointment_id, 'status', status)
- appointment_booked = True
- if status == 'Cancelled':
- appointment_booked = False
- cancel_appointment(appointment_id)
-
- procedure_prescription = frappe.db.get_value('Patient Appointment', appointment_id, 'procedure_prescription')
- if procedure_prescription:
- frappe.db.set_value('Procedure Prescription', procedure_prescription, 'appointment_booked', appointment_booked)
-
-
-def send_confirmation_msg(doc):
- if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_confirmation'):
- message = frappe.db.get_single_value('Healthcare Settings', 'appointment_confirmation_msg')
- try:
- send_message(doc, message)
- except Exception:
- frappe.log_error(frappe.get_traceback(), _('Appointment Confirmation Message Not Sent'))
- frappe.msgprint(_('Appointment Confirmation Message Not Sent'), indicator='orange')
-
-
-@frappe.whitelist()
-def make_encounter(source_name, target_doc=None):
- doc = get_mapped_doc('Patient Appointment', source_name, {
- 'Patient Appointment': {
- 'doctype': 'Patient Encounter',
- 'field_map': [
- ['appointment', 'name'],
- ['patient', 'patient'],
- ['practitioner', 'practitioner'],
- ['medical_department', 'department'],
- ['patient_sex', 'patient_sex'],
- ['invoiced', 'invoiced'],
- ['company', 'company']
- ]
- }
- }, target_doc)
- return doc
-
-
-def send_appointment_reminder():
- if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_reminder'):
- remind_before = datetime.datetime.strptime(frappe.db.get_single_value('Healthcare Settings', 'remind_before'), '%H:%M:%S')
- reminder_dt = datetime.datetime.now() + datetime.timedelta(
- hours=remind_before.hour, minutes=remind_before.minute, seconds=remind_before.second)
-
- appointment_list = frappe.db.get_all('Patient Appointment', {
- 'appointment_datetime': ['between', (datetime.datetime.now(), reminder_dt)],
- 'reminded': 0,
- 'status': ['!=', 'Cancelled']
- })
-
- for appointment in appointment_list:
- doc = frappe.get_doc('Patient Appointment', appointment.name)
- message = frappe.db.get_single_value('Healthcare Settings', 'appointment_reminder_msg')
- send_message(doc, message)
- frappe.db.set_value('Patient Appointment', doc.name, 'reminded', 1)
-
-def send_message(doc, message):
- patient_mobile = frappe.db.get_value('Patient', doc.patient, 'mobile')
- if patient_mobile:
- context = {'doc': doc, 'alert': doc, 'comments': None}
- if doc.get('_comments'):
- context['comments'] = json.loads(doc.get('_comments'))
-
- # jinja to string convertion happens here
- message = frappe.render_template(message, context)
- number = [patient_mobile]
- try:
- send_sms(number, message)
- except Exception as e:
- frappe.msgprint(_('SMS not sent, please check SMS Settings'), alert=True)
-
-@frappe.whitelist()
-def get_events(start, end, filters=None):
- """Returns events for Gantt / Calendar view rendering.
-
- :param start: Start date-time.
- :param end: End date-time.
- :param filters: Filters (JSON).
- """
- from frappe.desk.calendar import get_event_conditions
- conditions = get_event_conditions('Patient Appointment', filters)
-
- data = frappe.db.sql("""
- select
- `tabPatient Appointment`.name, `tabPatient Appointment`.patient,
- `tabPatient Appointment`.practitioner, `tabPatient Appointment`.status,
- `tabPatient Appointment`.duration,
- timestamp(`tabPatient Appointment`.appointment_date, `tabPatient Appointment`.appointment_time) as 'start',
- `tabAppointment Type`.color
- from
- `tabPatient Appointment`
- left join `tabAppointment Type` on `tabPatient Appointment`.appointment_type=`tabAppointment Type`.name
- where
- (`tabPatient Appointment`.appointment_date between %(start)s and %(end)s)
- and `tabPatient Appointment`.status != 'Cancelled' and `tabPatient Appointment`.docstatus < 2 {conditions}""".format(conditions=conditions),
- {"start": start, "end": end}, as_dict=True, update={"allDay": 0})
-
- for item in data:
- item.end = item.start + datetime.timedelta(minutes = item.duration)
-
- return data
-
-
-@frappe.whitelist()
-def get_procedure_prescribed(patient):
- return frappe.db.sql(
- """
- SELECT
- pp.name, pp.procedure, pp.parent, ct.practitioner,
- ct.encounter_date, pp.practitioner, pp.date, pp.department
- FROM
- `tabPatient Encounter` ct, `tabProcedure Prescription` pp
- WHERE
- ct.patient=%(patient)s and pp.parent=ct.name and pp.appointment_booked=0
- ORDER BY
- ct.creation desc
- """, {'patient': patient}
- )
-
-
-@frappe.whitelist()
-def get_prescribed_therapies(patient):
- return frappe.db.sql(
- """
- SELECT
- t.therapy_type, t.name, t.parent, e.practitioner,
- e.encounter_date, e.therapy_plan, e.medical_department
- FROM
- `tabPatient Encounter` e, `tabTherapy Plan Detail` t
- WHERE
- e.patient=%(patient)s and t.parent=e.name
- ORDER BY
- e.creation desc
- """, {'patient': patient}
- )
-
-
-def update_appointment_status():
- # update the status of appointments daily
- appointments = frappe.get_all('Patient Appointment', {
- 'status': ('not in', ['Closed', 'Cancelled'])
- }, as_dict=1)
-
- for appointment in appointments:
- frappe.get_doc('Patient Appointment', appointment.name).set_status()
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js
deleted file mode 100644
index 2249d2a2059..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_calendar.js
+++ /dev/null
@@ -1,14 +0,0 @@
-
-frappe.views.calendar["Patient Appointment"] = {
- field_map: {
- "start": "start",
- "end": "end",
- "id": "name",
- "title": "patient",
- "allDay": "allDay",
- "eventColor": "color"
- },
- order_by: "appointment_date",
- gantt: true,
- get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events"
-};
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
deleted file mode 100644
index 43c63c96e6d..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'appointment',
- 'non_standard_fieldnames': {
- 'Patient Medical Record': 'reference_name'
- },
- 'transactions': [
- {
- 'label': _('Consultations'),
- 'items': ['Patient Encounter', 'Vital Signs', 'Patient Medical Record']
- }
- ]
- }
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js
deleted file mode 100644
index 721887b4593..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
-(c) ESS 2015-16
-*/
-frappe.listview_settings['Patient Appointment'] = {
- filters: [["status", "=", "Open"]],
- get_indicator: function(doc) {
- var colors = {
- "Open": "orange",
- "Scheduled": "yellow",
- "Closed": "green",
- "Cancelled": "red",
- "Expired": "grey"
- };
- return [__(doc.status), colors[doc.status], "status,=," + doc.status];
- }
-};
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
deleted file mode 100644
index 8ca30b8cbe0..00000000000
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ /dev/null
@@ -1,487 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-import frappe
-from frappe.utils import add_days, now_datetime, nowdate
-
-from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
-from erpnext.healthcare.doctype.patient_appointment.patient_appointment import (
- check_is_new_patient,
- check_payment_fields_reqd,
- make_encounter,
- update_status,
-)
-
-
-class TestPatientAppointment(unittest.TestCase):
- def setUp(self):
- frappe.db.sql("""delete from `tabPatient Appointment`""")
- frappe.db.sql("""delete from `tabFee Validity`""")
- frappe.db.sql("""delete from `tabPatient Encounter`""")
- make_pos_profile()
- frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test %'""")
- frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test Service Unit Type%'""")
-
- def test_status(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
- appointment = create_appointment(patient, practitioner, nowdate())
- self.assertEqual(appointment.status, 'Open')
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2))
- self.assertEqual(appointment.status, 'Scheduled')
- encounter = create_encounter(appointment)
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
- encounter.cancel()
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
-
- def test_start_encounter(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), invoice = 1)
- appointment.reload()
- self.assertEqual(appointment.invoiced, 1)
- encounter = make_encounter(appointment.name)
- self.assertTrue(encounter)
- self.assertEqual(encounter.company, appointment.company)
- self.assertEqual(encounter.practitioner, appointment.practitioner)
- self.assertEqual(encounter.patient, appointment.patient)
- # invoiced flag mapped from appointment
- self.assertEqual(encounter.invoiced, frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'))
-
- def test_auto_invoicing(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
- appointment = create_appointment(patient, practitioner, nowdate())
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 0)
-
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), invoice=1)
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 1)
- sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
- self.assertTrue(sales_invoice_name)
- self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'company'), appointment.company)
- self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'patient'), appointment.patient)
- self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
-
- def test_auto_invoicing_based_on_department(self):
- patient, practitioner = create_healthcare_docs()
- medical_department = create_medical_department()
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment_type = create_appointment_type({'medical_department': medical_department})
-
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
- invoice=1, appointment_type=appointment_type.name, department=medical_department)
- appointment.reload()
-
- self.assertEqual(appointment.invoiced, 1)
- self.assertEqual(appointment.billing_item, 'HLC-SI-001')
- self.assertEqual(appointment.paid_amount, 200)
-
- sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
- self.assertTrue(sales_invoice_name)
- self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
-
- def test_auto_invoicing_according_to_appointment_type_charge(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
-
- item = create_healthcare_service_items()
- items = [{
- 'op_consulting_charge_item': item,
- 'op_consulting_charge': 300
- }]
- appointment_type = create_appointment_type(args={
- 'name': 'Generic Appointment Type charge',
- 'items': items
- })
-
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
- invoice=1, appointment_type=appointment_type.name)
- appointment.reload()
-
- self.assertEqual(appointment.invoiced, 1)
- self.assertEqual(appointment.billing_item, item)
- self.assertEqual(appointment.paid_amount, 300)
-
- sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
- self.assertTrue(sales_invoice_name)
-
- def test_appointment_cancel(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
- appointment = create_appointment(patient, practitioner, nowdate())
- fee_validity = frappe.db.get_value('Fee Validity', {'patient': patient, 'practitioner': practitioner})
- # fee validity created
- self.assertTrue(fee_validity)
-
- # first follow up appointment
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1))
- self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 1)
-
- update_status(appointment.name, 'Cancelled')
- # check fee validity updated
- self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 0)
-
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1), invoice=1)
- update_status(appointment.name, 'Cancelled')
- # check invoice cancelled
- sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
- self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'status'), 'Cancelled')
-
- def test_appointment_booking_for_admission_service_unit(self):
- from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
- admit_patient,
- discharge_patient,
- schedule_discharge,
- )
- from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
- create_inpatient,
- get_healthcare_service_unit,
- mark_invoiced_inpatient_occupancy,
- )
-
- frappe.db.sql("""delete from `tabInpatient Record`""")
- patient, practitioner = create_healthcare_docs()
- patient = create_patient()
- # Schedule Admission
- ip_record = create_inpatient(patient)
- ip_record.expected_length_of_stay = 0
- ip_record.save(ignore_permissions = True)
-
- # Admit
- service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy')
- admit_patient(ip_record, service_unit, now_datetime())
-
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit)
- self.assertEqual(appointment.service_unit, service_unit)
-
- # Discharge
- schedule_discharge(frappe.as_json({'patient': patient}))
- ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name)
- mark_invoiced_inpatient_occupancy(ip_record1)
- discharge_patient(ip_record1)
-
- def test_invalid_healthcare_service_unit_validation(self):
- from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
- admit_patient,
- discharge_patient,
- schedule_discharge,
- )
- from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
- create_inpatient,
- get_healthcare_service_unit,
- mark_invoiced_inpatient_occupancy,
- )
-
- frappe.db.sql("""delete from `tabInpatient Record`""")
- patient, practitioner = create_healthcare_docs()
- patient = create_patient()
- # Schedule Admission
- ip_record = create_inpatient(patient)
- ip_record.expected_length_of_stay = 0
- ip_record.save(ignore_permissions = True)
-
- # Admit
- service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy')
- admit_patient(ip_record, service_unit, now_datetime())
-
- appointment_service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy for Appointment')
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=appointment_service_unit, save=0)
- self.assertRaises(frappe.exceptions.ValidationError, appointment.save)
-
- # Discharge
- schedule_discharge(frappe.as_json({'patient': patient}))
- ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name)
- mark_invoiced_inpatient_occupancy(ip_record1)
- discharge_patient(ip_record1)
-
- def test_payment_should_be_mandatory_for_new_patient_appointment(self):
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- frappe.db.set_value('Healthcare Settings', None, 'max_visits', 3)
- frappe.db.set_value('Healthcare Settings', None, 'valid_days', 30)
-
- patient = create_patient()
- assert check_is_new_patient(patient)
- payment_required = check_payment_fields_reqd(patient)
- assert payment_required is True
-
- def test_sales_invoice_should_be_generated_for_new_patient_appointment(self):
- patient, practitioner = create_healthcare_docs()
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- invoice_count = frappe.db.count('Sales Invoice')
-
- assert check_is_new_patient(patient)
- create_appointment(patient, practitioner, nowdate())
- new_invoice_count = frappe.db.count('Sales Invoice')
-
- assert new_invoice_count == invoice_count + 1
-
- def test_patient_appointment_should_consider_permissions_while_fetching_appointments(self):
- patient, practitioner = create_healthcare_docs()
- create_appointment(patient, practitioner, nowdate())
-
- patient, new_practitioner = create_healthcare_docs(id=5)
- create_appointment(patient, new_practitioner, nowdate())
-
- roles = [{"doctype": "Has Role", "role": "Physician"}]
- user = create_user(roles=roles)
- new_practitioner = frappe.get_doc('Healthcare Practitioner', new_practitioner)
- new_practitioner.user_id = user.email
- new_practitioner.save()
-
- frappe.set_user(user.name)
- appointments = frappe.get_list('Patient Appointment')
- assert len(appointments) == 1
-
- frappe.set_user("Administrator")
- appointments = frappe.get_list('Patient Appointment')
- assert len(appointments) == 2
-
- def test_overlap_appointment(self):
- from erpnext.healthcare.doctype.patient_appointment.patient_appointment import OverlapError
- patient, practitioner = create_healthcare_docs(id=1)
- patient_1, practitioner_1 = create_healthcare_docs(id=2)
- service_unit = create_service_unit(id=0)
- service_unit_1 = create_service_unit(id=1)
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit) # valid
-
- # patient and practitioner cannot have overlapping appointments
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit, save=0)
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit_1, save=0) # diff service unit
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient, practitioner, nowdate(), save=0) # with no service unit link
- self.assertRaises(OverlapError, appointment.save)
-
- # patient cannot have overlapping appointments with other practitioners
- appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit, save=0)
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit_1, save=0)
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient, practitioner_1, nowdate(), save=0)
- self.assertRaises(OverlapError, appointment.save)
-
- # practitioner cannot have overlapping appointments with other patients
- appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit, save=0)
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit_1, save=0)
- self.assertRaises(OverlapError, appointment.save)
- appointment = create_appointment(patient_1, practitioner, nowdate(), save=0)
- self.assertRaises(OverlapError, appointment.save)
-
- def test_service_unit_capacity(self):
- from erpnext.healthcare.doctype.patient_appointment.patient_appointment import (
- MaximumCapacityError,
- OverlapError,
- )
- practitioner = create_practitioner()
- capacity = 3
- overlap_service_unit_type = create_service_unit_type(id=10, allow_appointments=1, overlap_appointments=1)
- overlap_service_unit = create_service_unit(id=100, service_unit_type=overlap_service_unit_type, service_unit_capacity=capacity)
-
- for i in range(0, capacity):
- patient = create_patient(id=i)
- create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit) # valid
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0) # overlap
- self.assertRaises(OverlapError, appointment.save)
-
- patient = create_patient(id=capacity)
- appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0)
- self.assertRaises(MaximumCapacityError, appointment.save)
-
-
-def create_healthcare_docs(id=0):
- patient = create_patient(id)
- practitioner = create_practitioner(id)
-
- return patient, practitioner
-
-
-def create_patient(id=0):
- if frappe.db.exists('Patient', {'firstname':f'_Test Patient {str(id)}'}):
- patient = frappe.db.get_value('Patient', {'first_name': f'_Test Patient {str(id)}'}, ['name'])
- return patient
-
- patient = frappe.new_doc('Patient')
- patient.first_name = f'_Test Patient {str(id)}'
- patient.sex = 'Female'
- patient.save(ignore_permissions=True)
-
- return patient.name
-
-
-def create_medical_department(id=0):
- if frappe.db.exists('Medical Department', f'_Test Medical Department {str(id)}'):
- return f'_Test Medical Department {str(id)}'
-
- medical_department = frappe.new_doc('Medical Department')
- medical_department.department = f'_Test Medical Department {str(id)}'
- medical_department.save(ignore_permissions=True)
-
- return medical_department.name
-
-
-def create_practitioner(id=0, medical_department=None):
- if frappe.db.exists('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}):
- practitioner = frappe.db.get_value('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}, ['name'])
- return practitioner
-
- practitioner = frappe.new_doc('Healthcare Practitioner')
- practitioner.first_name = f'_Test Healthcare Practitioner {str(id)}'
- practitioner.gender = 'Female'
- practitioner.department = medical_department or create_medical_department(id)
- practitioner.op_consulting_charge = 500
- practitioner.inpatient_visit_charge = 500
- practitioner.save(ignore_permissions=True)
-
- return practitioner.name
-
-
-def create_encounter(appointment):
- if appointment:
- encounter = frappe.new_doc('Patient Encounter')
- encounter.appointment = appointment.name
- encounter.patient = appointment.patient
- encounter.practitioner = appointment.practitioner
- encounter.encounter_date = appointment.appointment_date
- encounter.encounter_time = appointment.appointment_time
- encounter.company = appointment.company
- encounter.save()
- encounter.submit()
-
- return encounter
-
-
-def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0,
- service_unit=None, appointment_type=None, save=1, department=None):
- item = create_healthcare_service_items()
- frappe.db.set_value('Healthcare Settings', None, 'inpatient_visit_charge_item', item)
- frappe.db.set_value('Healthcare Settings', None, 'op_consulting_charge_item', item)
- appointment = frappe.new_doc('Patient Appointment')
- appointment.patient = patient
- appointment.practitioner = practitioner
- appointment.department = department or '_Test Medical Department'
- appointment.appointment_date = appointment_date
- appointment.company = '_Test Company'
- appointment.duration = 15
-
- if service_unit:
- appointment.service_unit = service_unit
- if invoice:
- appointment.mode_of_payment = 'Cash'
- if appointment_type:
- appointment.appointment_type = appointment_type
- if procedure_template:
- appointment.procedure_template = create_clinical_procedure_template().get('name')
- if save:
- appointment.save(ignore_permissions=True)
-
- return appointment
-
-
-def create_healthcare_service_items():
- if frappe.db.exists('Item', 'HLC-SI-001'):
- return 'HLC-SI-001'
-
- item = frappe.new_doc('Item')
- item.item_code = 'HLC-SI-001'
- item.item_name = 'Consulting Charges'
- item.item_group = 'Services'
- item.is_stock_item = 0
- item.stock_uom = 'Nos'
- item.save()
-
- return item.name
-
-
-def create_clinical_procedure_template():
- if frappe.db.exists('Clinical Procedure Template', 'Knee Surgery and Rehab'):
- return frappe.get_doc('Clinical Procedure Template', 'Knee Surgery and Rehab')
-
- template = frappe.new_doc('Clinical Procedure Template')
- template.template = 'Knee Surgery and Rehab'
- template.item_code = 'Knee Surgery and Rehab'
- template.item_group = 'Services'
- template.is_billable = 1
- template.description = 'Knee Surgery and Rehab'
- template.rate = 50000
- template.save()
-
- return template
-
-
-def create_appointment_type(args=None):
- if not args:
- args = frappe.local.form_dict
-
- name = args.get('name') or 'Test Appointment Type wise Charge'
-
- if frappe.db.exists('Appointment Type', name):
- return frappe.get_doc('Appointment Type', name)
-
- else:
- item = create_healthcare_service_items()
- items = [{
- 'medical_department': args.get('medical_department') or '_Test Medical Department',
- 'op_consulting_charge_item': item,
- 'op_consulting_charge': 200
- }]
- return frappe.get_doc({
- 'doctype': 'Appointment Type',
- 'appointment_type': args.get('name') or 'Test Appointment Type wise Charge',
- 'default_duration': args.get('default_duration') or 20,
- 'color': args.get('color') or '#7575ff',
- 'price_list': args.get('price_list') or frappe.db.get_value("Price List", {"selling": 1}),
- 'items': args.get('items') or items
- }).insert()
-
-def create_user(email=None, roles=None):
- if not email:
- email = '{}@frappe.com'.format(frappe.utils.random_string(10))
- user = frappe.db.exists('User', email)
- if not user:
- user = frappe.get_doc({
- "doctype": "User",
- "email": email,
- "first_name": "test_user",
- "password": "password",
- "roles": roles,
- }).insert()
- return user
-
-
-def create_service_unit_type(id=0, allow_appointments=1, overlap_appointments=0):
- if frappe.db.exists('Healthcare Service Unit Type', f'_Test Service Unit Type {str(id)}'):
- return f'_Test Service Unit Type {str(id)}'
-
- service_unit_type = frappe.new_doc('Healthcare Service Unit Type')
- service_unit_type.service_unit_type = f'_Test Service Unit Type {str(id)}'
- service_unit_type.allow_appointments = allow_appointments
- service_unit_type.overlap_appointments = overlap_appointments
- service_unit_type.save(ignore_permissions=True)
-
- return service_unit_type.name
-
-
-def create_service_unit(id=0, service_unit_type=None, service_unit_capacity=0):
- if frappe.db.exists('Healthcare Service Unit', f'_Test Service Unit {str(id)}'):
- return f'_Test service_unit {str(id)}'
-
- service_unit = frappe.new_doc('Healthcare Service Unit')
- service_unit.is_group = 0
- service_unit.healthcare_service_unit_name= f'_Test Service Unit {str(id)}'
- service_unit.service_unit_type = service_unit_type or create_service_unit_type(id)
- service_unit.service_unit_capacity = service_unit_capacity
- service_unit.save(ignore_permissions=True)
-
- return service_unit.name
diff --git a/erpnext/healthcare/doctype/patient_assessment/__init__.py b/erpnext/healthcare/doctype/patient_assessment/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js
deleted file mode 100644
index f28d32c22c7..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.js
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient Assessment', {
- refresh: function(frm) {
- if (frm.doc.assessment_template) {
- frm.trigger('set_score_range');
- }
-
- if (!frm.doc.__islocal) {
- frm.trigger('show_patient_progress');
- }
- },
-
- assessment_template: function(frm) {
- if (frm.doc.assessment_template) {
- frappe.call({
- 'method': 'frappe.client.get',
- args: {
- doctype: 'Patient Assessment Template',
- name: frm.doc.assessment_template
- },
- callback: function(data) {
- frm.doc.assessment_sheet = [];
- $.each(data.message.parameters, function(_i, e) {
- let entry = frm.add_child('assessment_sheet');
- entry.parameter = e.assessment_parameter;
- });
-
- frm.set_value('scale_min', data.message.scale_min);
- frm.set_value('scale_max', data.message.scale_max);
- frm.set_value('assessment_description', data.message.assessment_description);
- frm.set_value('total_score', data.message.scale_max * data.message.parameters.length);
- frm.trigger('set_score_range');
- refresh_field('assessment_sheet');
- }
- });
- }
- },
-
- set_score_range: function(frm) {
- let options = [''];
- for(let i = frm.doc.scale_min; i <= frm.doc.scale_max; i++) {
- options.push(i);
- }
- frm.fields_dict.assessment_sheet.grid.update_docfield_property(
- 'score', 'options', options
- );
- },
-
- calculate_total_score: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- let total_score = 0;
- $.each(frm.doc.assessment_sheet || [], function(_i, item) {
- if (item.score) {
- total_score += parseInt(item.score);
- }
- });
-
- frm.set_value('total_score_obtained', total_score);
- },
-
- show_patient_progress: function(frm) {
- let bars = [];
- let message = '';
- let added_min = false;
-
- let title = __('{0} out of {1}', [frm.doc.total_score_obtained, frm.doc.total_score]);
-
- bars.push({
- 'title': title,
- 'width': (frm.doc.total_score_obtained / frm.doc.total_score * 100) + '%',
- 'progress_class': 'progress-bar-success'
- });
- if (bars[0].width == '0%') {
- bars[0].width = '0.5%';
- added_min = 0.5;
- }
- message = title;
- frm.dashboard.add_progress(__('Status'), bars, message);
- },
-});
-
-frappe.ui.form.on('Patient Assessment Sheet', {
- score: function(frm, cdt, cdn) {
- frm.events.calculate_total_score(frm, cdt, cdn);
- }
-});
diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json
deleted file mode 100644
index eb0021ff758..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.json
+++ /dev/null
@@ -1,181 +0,0 @@
-{
- "actions": [],
- "autoname": "naming_series:",
- "creation": "2020-04-19 22:45:12.356209",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "therapy_session",
- "patient",
- "assessment_template",
- "column_break_4",
- "company",
- "healthcare_practitioner",
- "assessment_datetime",
- "assessment_description",
- "section_break_7",
- "assessment_sheet",
- "section_break_9",
- "total_score_obtained",
- "column_break_11",
- "total_score",
- "scale_min",
- "scale_max",
- "amended_from"
- ],
- "fields": [
- {
- "fetch_from": "therapy_session.patient",
- "fieldname": "patient",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1
- },
- {
- "fieldname": "assessment_template",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Assessment Template",
- "options": "Patient Assessment Template",
- "reqd": 1
- },
- {
- "fieldname": "therapy_session",
- "fieldtype": "Link",
- "label": "Therapy Session",
- "options": "Therapy Session"
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "therapy_session.practitioner",
- "fieldname": "healthcare_practitioner",
- "fieldtype": "Link",
- "label": "Healthcare Practitioner",
- "options": "Healthcare Practitioner"
- },
- {
- "fieldname": "assessment_datetime",
- "fieldtype": "Datetime",
- "label": "Assessment Datetime",
- "reqd": 1
- },
- {
- "fieldname": "section_break_7",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "assessment_sheet",
- "fieldtype": "Table",
- "label": "Assessment Sheet",
- "options": "Patient Assessment Sheet"
- },
- {
- "fieldname": "section_break_9",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "total_score",
- "fieldtype": "Int",
- "label": "Total Score",
- "read_only": 1
- },
- {
- "fieldname": "column_break_11",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "total_score_obtained",
- "fieldtype": "Int",
- "label": "Total Score Obtained",
- "read_only": 1
- },
- {
- "fieldname": "scale_min",
- "fieldtype": "Int",
- "hidden": 1,
- "label": "Scale Min",
- "read_only": 1
- },
- {
- "fieldname": "scale_max",
- "fieldtype": "Int",
- "hidden": 1,
- "label": "Scale Max",
- "read_only": 1
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Naming Series",
- "options": "HLC-PA-.YYYY.-"
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Patient Assessment",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "assessment_description",
- "fieldtype": "Small Text",
- "label": "Assessment Description"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Company",
- "options": "Company"
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2020-06-25 00:25:13.208400",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Assessment",
- "owner": "Administrator",
- "permissions": [
- {
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "cancel": 1,
- "create": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
deleted file mode 100644
index 90cb30035d4..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment/patient_assessment.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
-
-
-class PatientAssessment(Document):
- def validate(self):
- self.set_total_score()
-
- def set_total_score(self):
- total_score = 0
- for entry in self.assessment_sheet:
- total_score += int(entry.score)
- self.total_score_obtained = total_score
-
-@frappe.whitelist()
-def create_patient_assessment(source_name, target_doc=None):
- doc = get_mapped_doc('Therapy Session', source_name, {
- 'Therapy Session': {
- 'doctype': 'Patient Assessment',
- 'field_map': [
- ['therapy_session', 'name'],
- ['patient', 'patient'],
- ['practitioner', 'practitioner']
- ]
- }
- }, target_doc)
-
- return doc
diff --git a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py b/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py
deleted file mode 100644
index 0ffbd1f5049..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment/test_patient_assessment.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-
-class TestPatientAssessment(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/__init__.py b/erpnext/healthcare/doctype/patient_assessment_detail/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json
deleted file mode 100644
index 179f441044e..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "actions": [],
- "creation": "2020-04-19 19:33:00.115395",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "assessment_parameter"
- ],
- "fields": [
- {
- "fieldname": "assessment_parameter",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Assessment Parameter",
- "options": "Patient Assessment Parameter",
- "reqd": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-04-19 19:33:00.115395",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Assessment Detail",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py b/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py
deleted file mode 100644
index 4da679b8892..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_detail/patient_assessment_detail.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientAssessmentDetail(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/__init__.py b/erpnext/healthcare/doctype/patient_assessment_parameter/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js
deleted file mode 100644
index 2c5d270d575..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient Assessment Parameter', {
- // refresh: function(frm) {
-
- // }
-});
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json
deleted file mode 100644
index 098bdefea70..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "actions": [],
- "autoname": "field:assessment_parameter",
- "creation": "2020-04-15 14:34:46.551042",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "assessment_parameter"
- ],
- "fields": [
- {
- "fieldname": "assessment_parameter",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Assessment Parameter",
- "reqd": 1,
- "unique": 1
- }
- ],
- "links": [],
- "modified": "2020-04-20 09:22:19.135196",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Assessment Parameter",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py
deleted file mode 100644
index 783c5378481..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/patient_assessment_parameter.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientAssessmentParameter(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py b/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py
deleted file mode 100644
index f06fffb1ef4..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_parameter/test_patient_assessment_parameter.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-
-class TestPatientAssessmentParameter(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/__init__.py b/erpnext/healthcare/doctype/patient_assessment_sheet/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json
deleted file mode 100644
index 64e4aef7cf0..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "actions": [],
- "creation": "2020-04-19 23:07:02.220244",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "parameter",
- "score",
- "time",
- "column_break_4",
- "comments"
- ],
- "fields": [
- {
- "fieldname": "parameter",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Parameter",
- "options": "Patient Assessment Parameter",
- "reqd": 1
- },
- {
- "fieldname": "score",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Score",
- "reqd": 1
- },
- {
- "fieldname": "time",
- "fieldtype": "Time",
- "label": "Time"
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "comments",
- "fieldtype": "Small Text",
- "label": "Comments"
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-04-20 09:56:28.746619",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Assessment Sheet",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py b/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py
deleted file mode 100644
index 4686e9e2617..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_sheet/patient_assessment_sheet.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientAssessmentSheet(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/__init__.py b/erpnext/healthcare/doctype/patient_assessment_template/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js
deleted file mode 100644
index 40419362a4a..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient Assessment Template', {
- // refresh: function(frm) {
-
- // }
-});
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json
deleted file mode 100644
index de006b18056..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.json
+++ /dev/null
@@ -1,109 +0,0 @@
-{
- "actions": [],
- "autoname": "field:assessment_name",
- "creation": "2020-04-19 19:33:13.204707",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "assessment_name",
- "section_break_2",
- "parameters",
- "assessment_scale_details_section",
- "scale_min",
- "scale_max",
- "column_break_8",
- "assessment_description"
- ],
- "fields": [
- {
- "fieldname": "parameters",
- "fieldtype": "Table",
- "label": "Parameters",
- "options": "Patient Assessment Detail"
- },
- {
- "fieldname": "assessment_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Assessment Name",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "section_break_2",
- "fieldtype": "Section Break",
- "label": "Assessment Parameters"
- },
- {
- "fieldname": "assessment_scale_details_section",
- "fieldtype": "Section Break",
- "label": "Assessment Scale"
- },
- {
- "fieldname": "scale_min",
- "fieldtype": "Int",
- "label": "Scale Minimum"
- },
- {
- "fieldname": "scale_max",
- "fieldtype": "Int",
- "label": "Scale Maximum"
- },
- {
- "fieldname": "column_break_8",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "assessment_description",
- "fieldtype": "Small Text",
- "label": "Assessment Description"
- }
- ],
- "links": [],
- "modified": "2020-04-21 13:14:19.075167",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Assessment Template",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py
deleted file mode 100644
index e0d8fca37f7..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_template/patient_assessment_template.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientAssessmentTemplate(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py b/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py
deleted file mode 100644
index 7d639cb6af4..00000000000
--- a/erpnext/healthcare/doctype/patient_assessment_template/test_patient_assessment_template.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-
-class TestPatientAssessmentTemplate(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/patient_encounter/__init__.py b/erpnext/healthcare/doctype/patient_encounter/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
deleted file mode 100644
index c3466260d2b..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
+++ /dev/null
@@ -1,397 +0,0 @@
-// Copyright (c) 2016, ESS LLP and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient Encounter', {
- setup: function(frm) {
- frm.get_field('therapies').grid.editable_fields = [
- {fieldname: 'therapy_type', columns: 8},
- {fieldname: 'no_of_sessions', columns: 2}
- ];
- frm.get_field('drug_prescription').grid.editable_fields = [
- {fieldname: 'drug_code', columns: 2},
- {fieldname: 'drug_name', columns: 2},
- {fieldname: 'dosage', columns: 2},
- {fieldname: 'period', columns: 2}
- ];
- frm.get_field('lab_test_prescription').grid.editable_fields = [
- {fieldname: 'lab_test_code', columns: 2},
- {fieldname: 'lab_test_name', columns: 4},
- {fieldname: 'lab_test_comment', columns: 4}
- ];
- },
-
- refresh: function(frm) {
- refresh_field('drug_prescription');
- refresh_field('lab_test_prescription');
-
- if (!frm.doc.__islocal) {
- if (frm.doc.docstatus === 1) {
- if (frm.doc.inpatient_status == 'Admission Scheduled' || frm.doc.inpatient_status == 'Admitted') {
- frm.add_custom_button(__('Schedule Discharge'), function() {
- schedule_discharge(frm);
- });
- } else if (frm.doc.inpatient_status != 'Discharge Scheduled') {
- frm.add_custom_button(__('Schedule Admission'), function() {
- schedule_inpatient(frm);
- });
- }
- }
-
- frm.add_custom_button(__('Patient History'), function() {
- if (frm.doc.patient) {
- frappe.route_options = {'patient': frm.doc.patient};
- frappe.set_route('patient_history');
- } else {
- frappe.msgprint(__('Please select Patient'));
- }
- },'View');
-
- frm.add_custom_button(__('Vital Signs'), function() {
- create_vital_signs(frm);
- },'Create');
-
- frm.add_custom_button(__('Medical Record'), function() {
- create_medical_record(frm);
- },'Create');
-
- frm.add_custom_button(__('Clinical Procedure'), function() {
- create_procedure(frm);
- },'Create');
-
- if (frm.doc.drug_prescription && frm.doc.inpatient_record && frm.doc.inpatient_status === "Admitted") {
- frm.add_custom_button(__('Inpatient Medication Order'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.healthcare.doctype.patient_encounter.patient_encounter.make_ip_medication_order',
- frm: frm
- });
- }, 'Create');
- }
- }
-
- frm.set_query('patient', function() {
- return {
- filters: {'status': 'Active'}
- };
- });
-
- frm.set_query('drug_code', 'drug_prescription', function() {
- return {
- filters: {
- is_stock_item: 1
- }
- };
- });
-
- frm.set_query('lab_test_code', 'lab_test_prescription', function() {
- return {
- filters: {
- is_billable: 1
- }
- };
- });
-
- frm.set_query('appointment', function() {
- return {
- filters: {
- // Scheduled filter for demo ...
- status:['in',['Open','Scheduled']]
- }
- };
- });
-
- frm.set_df_property('patient', 'read_only', frm.doc.appointment ? 1 : 0);
- },
-
- appointment: function(frm) {
- frm.events.set_appointment_fields(frm);
- },
-
- patient: function(frm) {
- frm.events.set_patient_info(frm);
- },
-
- practitioner: function(frm) {
- if (!frm.doc.practitioner) {
- frm.set_value('practitioner_name', '');
- }
- },
- set_appointment_fields: function(frm) {
- if (frm.doc.appointment) {
- frappe.call({
- method: 'frappe.client.get',
- args: {
- doctype: 'Patient Appointment',
- name: frm.doc.appointment
- },
- callback: function(data) {
- let values = {
- 'patient':data.message.patient,
- 'type': data.message.appointment_type,
- 'practitioner': data.message.practitioner,
- 'invoiced': data.message.invoiced,
- 'company': data.message.company
- };
- frm.set_value(values);
- frm.set_df_property('patient', 'read_only', 1);
- }
- });
- }
- else {
- let values = {
- 'patient': '',
- 'patient_name': '',
- 'type': '',
- 'practitioner': '',
- 'invoiced': 0,
- 'patient_sex': '',
- 'patient_age': '',
- 'inpatient_record': '',
- 'inpatient_status': ''
- };
- frm.set_value(values);
- frm.set_df_property('patient', 'read_only', 0);
- }
- },
-
- set_patient_info: function(frm) {
- if (frm.doc.patient) {
- frappe.call({
- method: 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
- args: {
- patient: frm.doc.patient
- },
- callback: function(data) {
- let age = '';
- if (data.message.dob) {
- age = calculate_age(data.message.dob);
- }
- let values = {
- 'patient_age': age,
- 'patient_name':data.message.patient_name,
- 'patient_sex': data.message.sex,
- 'inpatient_record': data.message.inpatient_record,
- 'inpatient_status': data.message.inpatient_status
- };
- frm.set_value(values);
- }
- });
- } else {
- let values = {
- 'patient_age': '',
- 'patient_name':'',
- 'patient_sex': '',
- 'inpatient_record': '',
- 'inpatient_status': ''
- };
- frm.set_value(values);
- }
- },
-
- get_applicable_treatment_plans: function(frm) {
- frappe.call({
- method: 'get_applicable_treatment_plans',
- doc: frm.doc,
- args: {'encounter': frm.doc},
- freeze: true,
- freeze_message: __('Fetching Treatment Plans'),
- callback: function() {
- new frappe.ui.form.MultiSelectDialog({
- doctype: "Treatment Plan Template",
- target: this.cur_frm,
- setters: {
- medical_department: "",
- },
- action(selections) {
- frappe.call({
- method: 'set_treatment_plans',
- doc: frm.doc,
- args: selections,
- }).then(() => {
- frm.refresh_field('drug_prescription');
- frm.refresh_field('procedure_prescription');
- frm.refresh_field('lab_test_prescription');
- frm.refresh_field('therapies');
- });
- cur_dialog.hide();
- }
- });
-
-
- }
- });
- },
-
-});
-
-var schedule_inpatient = function(frm) {
- var dialog = new frappe.ui.Dialog({
- title: 'Patient Admission',
- fields: [
- {fieldtype: 'Link', label: 'Medical Department', fieldname: 'medical_department', options: 'Medical Department', reqd: 1},
- {fieldtype: 'Link', label: 'Healthcare Practitioner (Primary)', fieldname: 'primary_practitioner', options: 'Healthcare Practitioner', reqd: 1},
- {fieldtype: 'Link', label: 'Healthcare Practitioner (Secondary)', fieldname: 'secondary_practitioner', options: 'Healthcare Practitioner'},
- {fieldtype: 'Column Break'},
- {fieldtype: 'Date', label: 'Admission Ordered For', fieldname: 'admission_ordered_for', default: 'Today'},
- {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'},
- {fieldtype: 'Int', label: 'Expected Length of Stay', fieldname: 'expected_length_of_stay'},
- {fieldtype: 'Section Break'},
- {fieldtype: 'Long Text', label: 'Admission Instructions', fieldname: 'admission_instruction'}
- ],
- primary_action_label: __('Order Admission'),
- primary_action : function() {
- var args = {
- patient: frm.doc.patient,
- admission_encounter: frm.doc.name,
- referring_practitioner: frm.doc.practitioner,
- company: frm.doc.company,
- medical_department: dialog.get_value('medical_department'),
- primary_practitioner: dialog.get_value('primary_practitioner'),
- secondary_practitioner: dialog.get_value('secondary_practitioner'),
- admission_ordered_for: dialog.get_value('admission_ordered_for'),
- admission_service_unit_type: dialog.get_value('service_unit_type'),
- expected_length_of_stay: dialog.get_value('expected_length_of_stay'),
- admission_instruction: dialog.get_value('admission_instruction')
- }
- frappe.call({
- method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient',
- args: {
- args: args
- },
- callback: function(data) {
- if (!data.exc) {
- frm.reload_doc();
- }
- },
- freeze: true,
- freeze_message: __('Scheduling Patient Admission')
- });
- frm.refresh_fields();
- dialog.hide();
- }
- });
-
- dialog.set_values({
- 'medical_department': frm.doc.medical_department,
- 'primary_practitioner': frm.doc.practitioner,
- });
-
- dialog.fields_dict['service_unit_type'].get_query = function() {
- return {
- filters: {
- 'inpatient_occupancy': 1,
- 'allow_appointments': 0
- }
- };
- };
-
- dialog.show();
- dialog.$wrapper.find('.modal-dialog').css('width', '800px');
-};
-
-var schedule_discharge = function(frm) {
- var dialog = new frappe.ui.Dialog ({
- title: 'Inpatient Discharge',
- fields: [
- {fieldtype: 'Date', label: 'Discharge Ordered Date', fieldname: 'discharge_ordered_date', default: 'Today', read_only: 1},
- {fieldtype: 'Date', label: 'Followup Date', fieldname: 'followup_date'},
- {fieldtype: 'Column Break'},
- {fieldtype: 'Small Text', label: 'Discharge Instructions', fieldname: 'discharge_instructions'},
- {fieldtype: 'Section Break', label:'Discharge Summary'},
- {fieldtype: 'Long Text', label: 'Discharge Note', fieldname: 'discharge_note'}
- ],
- primary_action_label: __('Order Discharge'),
- primary_action : function() {
- var args = {
- patient: frm.doc.patient,
- discharge_encounter: frm.doc.name,
- discharge_practitioner: frm.doc.practitioner,
- discharge_ordered_date: dialog.get_value('discharge_ordered_date'),
- followup_date: dialog.get_value('followup_date'),
- discharge_instructions: dialog.get_value('discharge_instructions'),
- discharge_note: dialog.get_value('discharge_note')
- }
- frappe.call ({
- method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge',
- args: {args},
- callback: function(data) {
- if(!data.exc){
- frm.reload_doc();
- }
- },
- freeze: true,
- freeze_message: 'Scheduling Inpatient Discharge'
- });
- frm.refresh_fields();
- dialog.hide();
- }
- });
-
- dialog.show();
- dialog.$wrapper.find('.modal-dialog').css('width', '800px');
-};
-
-let create_medical_record = function(frm) {
- if (!frm.doc.patient) {
- frappe.throw(__('Please select patient'));
- }
- frappe.route_options = {
- 'patient': frm.doc.patient,
- 'status': 'Open',
- 'reference_doctype': 'Patient Medical Record',
- 'reference_owner': frm.doc.owner
- };
- frappe.new_doc('Patient Medical Record');
-};
-
-let create_vital_signs = function(frm) {
- if (!frm.doc.patient) {
- frappe.throw(__('Please select patient'));
- }
- frappe.route_options = {
- 'patient': frm.doc.patient,
- 'encounter': frm.doc.name,
- 'company': frm.doc.company
- };
- frappe.new_doc('Vital Signs');
-};
-
-let create_procedure = function(frm) {
- if (!frm.doc.patient) {
- frappe.throw(__('Please select patient'));
- }
- frappe.route_options = {
- 'patient': frm.doc.patient,
- 'medical_department': frm.doc.medical_department,
- 'company': frm.doc.company
- };
- frappe.new_doc('Clinical Procedure');
-};
-
-frappe.ui.form.on('Drug Prescription', {
- dosage: function(frm, cdt, cdn){
- frappe.model.set_value(cdt, cdn, 'update_schedule', 1);
- let child = locals[cdt][cdn];
- if (child.dosage) {
- frappe.model.set_value(cdt, cdn, 'interval_uom', 'Day');
- frappe.model.set_value(cdt, cdn, 'interval', 1);
- }
- },
- period: function(frm, cdt, cdn) {
- frappe.model.set_value(cdt, cdn, 'update_schedule', 1);
- },
- interval_uom: function(frm, cdt, cdn) {
- frappe.model.set_value(cdt, cdn, 'update_schedule', 1);
- let child = locals[cdt][cdn];
- if (child.interval_uom == 'Hour') {
- frappe.model.set_value(cdt, cdn, 'dosage', null);
- }
- }
-});
-
-let calculate_age = function(birth) {
- let ageMS = Date.parse(Date()) - Date.parse(birth);
- let age = new Date();
- age.setTime(ageMS);
- let years = age.getFullYear() - 1970;
- return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`;
-};
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
deleted file mode 100644
index 994597dca7c..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
+++ /dev/null
@@ -1,368 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "allow_import": 1,
- "autoname": "naming_series:",
- "beta": 1,
- "creation": "2016-04-21 10:53:44.637684",
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "title",
- "appointment",
- "appointment_type",
- "patient",
- "patient_name",
- "patient_sex",
- "patient_age",
- "inpatient_record",
- "inpatient_status",
- "column_break_6",
- "company",
- "encounter_date",
- "encounter_time",
- "practitioner",
- "practitioner_name",
- "medical_department",
- "invoiced",
- "sb_symptoms",
- "symptoms",
- "symptoms_in_print",
- "get_applicable_treatment_plans",
- "physical_examination",
- "diagnosis",
- "diagnosis_in_print",
- "codification",
- "codification_table",
- "sb_drug_prescription",
- "drug_prescription",
- "sb_test_prescription",
- "lab_test_prescription",
- "sb_procedures",
- "procedure_prescription",
- "rehabilitation_section",
- "therapy_plan",
- "therapies",
- "section_break_33",
- "encounter_comment",
- "sb_refs",
- "amended_from"
- ],
- "fields": [
- {
- "allow_on_submit": 1,
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "label": "Inpatient Record",
- "options": "Inpatient Record",
- "read_only": 1
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "no_copy": 1,
- "options": "HLC-ENC-.YYYY.-",
- "set_only_once": 1
- },
- {
- "fieldname": "appointment",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Appointment",
- "options": "Patient Appointment",
- "search_index": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_standard_filter": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1,
- "search_index": 1
- },
- {
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- },
- {
- "fieldname": "patient_age",
- "fieldtype": "Data",
- "label": "Age",
- "read_only": 1
- },
- {
- "fieldname": "patient_sex",
- "fieldtype": "Link",
- "label": "Gender",
- "options": "Gender",
- "read_only": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company"
- },
- {
- "fieldname": "column_break_6",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "practitioner",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Healthcare Practitioner",
- "options": "Healthcare Practitioner",
- "reqd": 1
- },
- {
- "default": "Today",
- "fieldname": "encounter_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Encounter Date",
- "reqd": 1
- },
- {
- "fieldname": "encounter_time",
- "fieldtype": "Time",
- "label": "Encounter Time",
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "label": "Invoiced",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "fieldname": "sb_symptoms",
- "fieldtype": "Section Break",
- "label": "Encounter Impression"
- },
- {
- "fieldname": "symptoms",
- "fieldtype": "Table MultiSelect",
- "ignore_xss_filter": 1,
- "label": "Symptoms",
- "no_copy": 1,
- "options": "Patient Encounter Symptom"
- },
- {
- "default": "0",
- "depends_on": "eval: doc.symptoms != ''",
- "fieldname": "symptoms_in_print",
- "fieldtype": "Check",
- "label": "In print",
- "no_copy": 1,
- "print_hide": 1,
- "report_hide": 1
- },
- {
- "fieldname": "physical_examination",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "diagnosis",
- "fieldtype": "Table MultiSelect",
- "ignore_xss_filter": 1,
- "label": "Diagnosis",
- "no_copy": 1,
- "options": "Patient Encounter Diagnosis"
- },
- {
- "default": "1",
- "depends_on": "eval: doc.diagnosis != ''",
- "fieldname": "diagnosis_in_print",
- "fieldtype": "Check",
- "label": "In print",
- "no_copy": 1,
- "print_hide": 1,
- "report_hide": 1
- },
- {
- "collapsible": 1,
- "fieldname": "codification",
- "fieldtype": "Section Break",
- "label": "Medical Coding"
- },
- {
- "fieldname": "codification_table",
- "fieldtype": "Table",
- "label": "Medical Codes",
- "options": "Codification Table"
- },
- {
- "fieldname": "sb_drug_prescription",
- "fieldtype": "Section Break",
- "label": "Medications"
- },
- {
- "fieldname": "drug_prescription",
- "fieldtype": "Table",
- "label": "Drug Prescription",
- "options": "Drug Prescription"
- },
- {
- "fieldname": "sb_test_prescription",
- "fieldtype": "Section Break",
- "label": "Investigations"
- },
- {
- "fieldname": "lab_test_prescription",
- "fieldtype": "Table",
- "label": "Lab Tests",
- "options": "Lab Prescription"
- },
- {
- "fieldname": "sb_procedures",
- "fieldtype": "Section Break",
- "label": "Procedures"
- },
- {
- "fieldname": "procedure_prescription",
- "fieldtype": "Table",
- "label": "Clinical Procedures",
- "no_copy": 1,
- "options": "Procedure Prescription"
- },
- {
- "fieldname": "encounter_comment",
- "fieldtype": "Small Text",
- "ignore_xss_filter": 1,
- "label": "Review Details",
- "no_copy": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Patient Encounter",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "rehabilitation_section",
- "fieldtype": "Section Break",
- "label": "Rehabilitation"
- },
- {
- "fieldname": "therapies",
- "fieldtype": "Table",
- "label": "Therapies",
- "options": "Therapy Plan Detail"
- },
- {
- "fieldname": "section_break_33",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "therapy_plan",
- "fieldtype": "Link",
- "hidden": 1,
- "label": "Therapy Plan",
- "options": "Therapy Plan",
- "read_only": 1
- },
- {
- "fieldname": "appointment_type",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Appointment Type",
- "no_copy": 1,
- "options": "Appointment Type",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1
- },
- {
- "fetch_from": "practitioner.department",
- "fieldname": "medical_department",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_standard_filter": 1,
- "label": "Department",
- "options": "Medical Department",
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "fieldname": "inpatient_status",
- "fieldtype": "Data",
- "label": "Inpatient Status",
- "read_only": 1
- },
- {
- "fieldname": "sb_refs",
- "fieldtype": "Section Break"
- },
- {
- "fetch_from": "practitioner.practitioner_name",
- "fieldname": "practitioner_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Practitioner Name",
- "read_only": 1
- },
- {
- "allow_on_submit": 1,
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Title",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "depends_on": "eval:doc.patient",
- "fieldname": "get_applicable_treatment_plans",
- "fieldtype": "Button",
- "label": "Get Applicable Treatment Plans"
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2021-07-27 11:39:12.347704",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Encounter",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient, practitioner, medical_department, encounter_date, encounter_time",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 1
-}
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
deleted file mode 100644
index 2daa6c145c8..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ /dev/null
@@ -1,182 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import add_days, getdate
-
-
-class PatientEncounter(Document):
- def validate(self):
- self.set_title()
-
- def on_update(self):
- if self.appointment:
- frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed')
-
- def on_submit(self):
- if self.therapies:
- create_therapy_plan(self)
-
- def on_cancel(self):
- if self.appointment:
- frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open')
-
- if self.inpatient_record and self.drug_prescription:
- delete_ip_medication_order(self)
-
- def set_title(self):
- self.title = _('{0} with {1}').format(self.patient_name or self.patient,
- self.practitioner_name or self.practitioner)[:100]
-
- @frappe.whitelist()
- @staticmethod
- def get_applicable_treatment_plans(encounter):
- patient = frappe.get_doc('Patient', encounter['patient'])
-
- plan_filters = {}
- plan_filters['name'] = ['in', []]
-
- age = patient.age
- if age:
- plan_filters['patient_age_from'] = ['<=', age.years]
- plan_filters['patient_age_to'] = ['>=', age.years]
-
- gender = patient.sex
- if gender:
- plan_filters['gender'] = ['in', [gender, None]]
-
- diagnosis = encounter.get('diagnosis')
- if diagnosis:
- diagnosis = [_diagnosis['diagnosis'] for _diagnosis in encounter['diagnosis']]
- filters = [
- ['diagnosis', 'in', diagnosis],
- ['parenttype', '=', 'Treatment Plan Template'],
- ]
- diagnosis = frappe.get_list('Patient Encounter Diagnosis', filters=filters, fields='*')
- plan_names = [_diagnosis['parent'] for _diagnosis in diagnosis]
- plan_filters['name'][1].extend(plan_names)
-
- symptoms = encounter.get('symptoms')
- if symptoms:
- symptoms = [symptom['complaint'] for symptom in encounter['symptoms']]
- filters = [
- ['complaint', 'in', symptoms],
- ['parenttype', '=', 'Treatment Plan Template'],
- ]
- symptoms = frappe.get_list('Patient Encounter Symptom', filters=filters, fields='*')
- plan_names = [symptom['parent'] for symptom in symptoms]
- plan_filters['name'][1].extend(plan_names)
-
- if not plan_filters['name'][1]:
- plan_filters.pop('name')
-
- plans = frappe.get_list('Treatment Plan Template', fields='*', filters=plan_filters)
-
- return plans
-
- @frappe.whitelist()
- def set_treatment_plans(self, treatment_plans=None):
- for treatment_plan in treatment_plans:
- self.set_treatment_plan(treatment_plan)
-
- def set_treatment_plan(self, plan):
- plan_items = frappe.get_list('Treatment Plan Template Item', filters={'parent': plan}, fields='*')
- for plan_item in plan_items:
- self.set_treatment_plan_item(plan_item)
-
- drugs = frappe.get_list('Drug Prescription', filters={'parent': plan}, fields='*')
- for drug in drugs:
- self.append('drug_prescription', drug)
-
- self.save()
-
- def set_treatment_plan_item(self, plan_item):
- if plan_item.type == 'Clinical Procedure Template':
- self.append('procedure_prescription', {
- 'procedure': plan_item.template
- })
-
- if plan_item.type == 'Lab Test Template':
- self.append('lab_test_prescription', {
- 'lab_test_code': plan_item.template
- })
-
- if plan_item.type == 'Therapy Type':
- self.append('therapies', {
- 'therapy_type': plan_item.template
- })
-
-
-@frappe.whitelist()
-def make_ip_medication_order(source_name, target_doc=None):
- def set_missing_values(source, target):
- target.start_date = source.encounter_date
- for entry in source.drug_prescription:
- if entry.drug_code:
- dosage = frappe.get_doc('Prescription Dosage', entry.dosage)
- dates = get_prescription_dates(entry.period, target.start_date)
- for date in dates:
- for dose in dosage.dosage_strength:
- order = target.append('medication_orders')
- order.drug = entry.drug_code
- order.drug_name = entry.drug_name
- order.dosage = dose.strength
- order.instructions = entry.comment
- order.dosage_form = entry.dosage_form
- order.date = date
- order.time = dose.strength_time
- target.end_date = dates[-1]
-
- doc = get_mapped_doc('Patient Encounter', source_name, {
- 'Patient Encounter': {
- 'doctype': 'Inpatient Medication Order',
- 'field_map': {
- 'name': 'patient_encounter',
- 'patient': 'patient',
- 'patient_name': 'patient_name',
- 'patient_age': 'patient_age',
- 'inpatient_record': 'inpatient_record',
- 'practitioner': 'practitioner',
- 'start_date': 'encounter_date'
- },
- }
- }, target_doc, set_missing_values)
-
- return doc
-
-
-def get_prescription_dates(period, start_date):
- prescription_duration = frappe.get_doc('Prescription Duration', period)
- days = prescription_duration.get_days()
- dates = [start_date]
- for i in range(1, days):
- dates.append(add_days(getdate(start_date), i))
- return dates
-
-
-def create_therapy_plan(encounter):
- if len(encounter.therapies):
- doc = frappe.new_doc('Therapy Plan')
- doc.patient = encounter.patient
- doc.start_date = encounter.encounter_date
- for entry in encounter.therapies:
- doc.append('therapy_plan_details', {
- 'therapy_type': entry.therapy_type,
- 'no_of_sessions': entry.no_of_sessions
- })
- doc.save(ignore_permissions=True)
- if doc.get('name'):
- encounter.db_set('therapy_plan', doc.name)
- frappe.msgprint(_('Therapy Plan {0} created successfully.').format(frappe.bold(doc.name)), alert=True)
-
-
-def delete_ip_medication_order(encounter):
- record = frappe.db.exists('Inpatient Medication Order', {'patient_encounter': encounter.name})
- if record:
- frappe.delete_doc('Inpatient Medication Order', record, force=1)
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
deleted file mode 100644
index 3b64d988715..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_dashboard.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'encounter',
- 'non_standard_fieldnames': {
- 'Patient Medical Record': 'reference_name',
- 'Inpatient Medication Order': 'patient_encounter'
- },
- 'transactions': [
- {
- 'label': _('Records'),
- 'items': ['Vital Signs', 'Patient Medical Record']
- },
- {
- 'label': _('Orders'),
- 'items': ['Inpatient Medication Order']
- }
- ],
- 'disable_create_buttons': ['Inpatient Medication Order']
- }
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js
deleted file mode 100644
index d8f63bd0fa5..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
-(c) ESS 2015-16
-*/
-frappe.listview_settings['Patient Encounter'] = {
- filters:[["docstatus","!=","2"]]
-};
diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
deleted file mode 100644
index fa643a31d8e..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-import frappe
-
-from erpnext.healthcare.doctype.patient_encounter.patient_encounter import PatientEncounter
-
-
-class TestPatientEncounter(unittest.TestCase):
- def setUp(self):
- try:
- gender_m = frappe.get_doc({
- 'doctype': 'Gender',
- 'gender': 'MALE'
- }).insert()
- gender_f = frappe.get_doc({
- 'doctype': 'Gender',
- 'gender': 'FEMALE'
- }).insert()
- except frappe.exceptions.DuplicateEntryError:
- gender_m = frappe.get_doc({
- 'doctype': 'Gender',
- 'gender': 'MALE'
- })
- gender_f = frappe.get_doc({
- 'doctype': 'Gender',
- 'gender': 'FEMALE'
- })
-
- self.patient_male = frappe.get_doc({
- 'doctype': 'Patient',
- 'first_name': 'John',
- 'sex': gender_m.gender,
- }).insert()
- self.patient_female = frappe.get_doc({
- 'doctype': 'Patient',
- 'first_name': 'Curie',
- 'sex': gender_f.gender,
- }).insert()
- self.practitioner = frappe.get_doc({
- 'doctype': 'Healthcare Practitioner',
- 'first_name': 'Doc',
- 'sex': 'MALE',
- }).insert()
- try:
- self.care_plan_male = frappe.get_doc({
- 'doctype': 'Treatment Plan Template',
- 'template_name': 'test plan - m',
- 'gender': gender_m.gender,
- }).insert()
- self.care_plan_female = frappe.get_doc({
- 'doctype': 'Treatment Plan Template',
- 'template_name': 'test plan - f',
- 'gender': gender_f.gender,
- }).insert()
- except frappe.exceptions.DuplicateEntryError:
- self.care_plan_male = frappe.get_doc({
- 'doctype': 'Treatment Plan Template',
- 'template_name': 'test plan - m',
- 'gender': gender_m.gender,
- })
- self.care_plan_female = frappe.get_doc({
- 'doctype': 'Treatment Plan Template',
- 'template_name': 'test plan - f',
- 'gender': gender_f.gender,
- })
-
- def test_treatment_plan_template_filter(self):
- encounter = frappe.get_doc({
- 'doctype': 'Patient Encounter',
- 'patient': self.patient_male.name,
- 'practitioner': self.practitioner.name,
- }).insert()
- plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
- self.assertEqual(plans[0]['name'], self.care_plan_male.template_name)
-
- encounter = frappe.get_doc({
- 'doctype': 'Patient Encounter',
- 'patient': self.patient_female.name,
- 'practitioner': self.practitioner.name,
- }).insert()
- plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
- self.assertEqual(plans[0]['name'], self.care_plan_female.template_name)
diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json
deleted file mode 100644
index 00ca309d63e..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "actions": [],
- "beta": 1,
- "creation": "2020-02-26 16:48:16.835105",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "diagnosis"
- ],
- "fields": [
- {
- "fieldname": "diagnosis",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Diagnosis",
- "options": "Diagnosis",
- "reqd": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-02-26 16:58:16.480583",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Encounter Diagnosis",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py
deleted file mode 100644
index e4d2069a50e..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientEncounterDiagnosis(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py b/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json
deleted file mode 100644
index bc921458674..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "actions": [],
- "beta": 1,
- "creation": "2020-02-26 16:47:00.525657",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "complaint"
- ],
- "fields": [
- {
- "fieldname": "complaint",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Complaint",
- "options": "Complaint",
- "reqd": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-02-26 16:57:37.997481",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Encounter Symptom",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py
deleted file mode 100644
index 47f2a2be7e9..00000000000
--- a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientEncounterSymptom(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json
deleted file mode 100644
index 3025c7b06d7..00000000000
--- a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "actions": [],
- "creation": "2020-11-25 13:40:23.054469",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "document_type",
- "date_fieldname",
- "add_edit_fields",
- "selected_fields"
- ],
- "fields": [
- {
- "fieldname": "document_type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Document Type",
- "options": "DocType",
- "reqd": 1
- },
- {
- "fieldname": "selected_fields",
- "fieldtype": "Code",
- "label": "Selected Fields",
- "read_only": 1
- },
- {
- "fieldname": "add_edit_fields",
- "fieldtype": "Button",
- "in_list_view": 1,
- "label": "Add / Edit Fields"
- },
- {
- "fieldname": "date_fieldname",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Date Fieldname",
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2020-11-30 13:54:37.474671",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient History Custom Document Type",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py b/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
deleted file mode 100644
index 34e15dc46a2..00000000000
--- a/erpnext/healthcare/doctype/patient_history_custom_document_type/patient_history_custom_document_type.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientHistoryCustomDocumentType(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_history_settings/__init__.py b/erpnext/healthcare/doctype/patient_history_settings/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js
deleted file mode 100644
index 453da6a12bf..00000000000
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.js
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient History Settings', {
- refresh: function(frm) {
- frm.set_query('document_type', 'custom_doctypes', () => {
- return {
- filters: {
- custom: 1,
- is_submittable: 1,
- module: 'Healthcare',
- }
- };
- });
- },
-
- field_selector: function(frm, doc, standard=1) {
- let document_fields = [];
- if (doc.selected_fields)
- document_fields = (JSON.parse(doc.selected_fields)).map(f => f.fieldname);
-
- frm.call({
- method: 'get_doctype_fields',
- doc: frm.doc,
- args: {
- document_type: doc.document_type,
- fields: document_fields
- },
- freeze: true,
- callback: function(r) {
- if (r.message) {
- let doctype = 'Patient History Custom Document Type';
- if (standard)
- doctype = 'Patient History Standard Document Type';
-
- frm.events.show_field_selector_dialog(frm, doc, doctype, r.message);
- }
- }
- });
- },
-
- show_field_selector_dialog: function(frm, doc, doctype, doc_fields) {
- let d = new frappe.ui.Dialog({
- title: __('{0} Fields', [__(doc.document_type)]),
- fields: [
- {
- label: __('Select Fields'),
- fieldtype: 'MultiCheck',
- fieldname: 'fields',
- options: doc_fields,
- columns: 2
- }
- ]
- });
-
- d.$body.prepend(`
-
-
-
`
- );
-
- frappe.utils.setup_search(d.$body, '.unit-checkbox', '.label-area');
-
- d.set_primary_action(__('Save'), () => {
- let values = d.get_values().fields;
-
- let selected_fields = [];
-
- frappe.model.with_doctype(doc.document_type, function() {
- for (let idx in values) {
- let value = values[idx];
-
- let field = frappe.get_meta(doc.document_type).fields.filter((df) => df.fieldname == value)[0];
- if (field) {
- selected_fields.push({
- label: field.label,
- fieldname: field.fieldname,
- fieldtype: field.fieldtype
- });
- }
- }
-
- d.refresh();
- frappe.model.set_value(doctype, doc.name, 'selected_fields', JSON.stringify(selected_fields));
- });
-
- d.hide();
- });
-
- d.show();
- },
-
- get_date_field_for_dt: function(frm, row) {
- frm.call({
- method: 'get_date_field_for_dt',
- doc: frm.doc,
- args: {
- document_type: row.document_type
- },
- callback: function(data) {
- if (data.message) {
- frappe.model.set_value('Patient History Custom Document Type',
- row.name, 'date_fieldname', data.message);
- }
- }
- });
- }
-});
-
-frappe.ui.form.on('Patient History Custom Document Type', {
- document_type: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- if (row.document_type) {
- frm.events.get_date_field_for_dt(frm, row);
- }
- },
-
- add_edit_fields: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- if (row.document_type) {
- frm.events.field_selector(frm, row, 0);
- }
- }
-});
-
-frappe.ui.form.on('Patient History Standard Document Type', {
- add_edit_fields: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- if (row.document_type) {
- frm.events.field_selector(frm, row);
- }
- }
-});
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json
deleted file mode 100644
index 143e2c91eb5..00000000000
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "actions": [],
- "creation": "2020-11-25 13:41:37.675518",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "standard_doctypes",
- "section_break_2",
- "custom_doctypes"
- ],
- "fields": [
- {
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "custom_doctypes",
- "fieldtype": "Table",
- "label": "Custom Document Types",
- "options": "Patient History Custom Document Type"
- },
- {
- "fieldname": "standard_doctypes",
- "fieldtype": "Table",
- "label": "Standard Document Types",
- "options": "Patient History Standard Document Type",
- "read_only": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "issingle": 1,
- "links": [],
- "modified": "2020-11-25 13:43:38.511771",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient History Settings",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
deleted file mode 100644
index b763591d3ac..00000000000
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from frappe.utils import cint, cstr
-
-from erpnext.healthcare.page.patient_history.patient_history import get_patient_history_doctypes
-
-
-class PatientHistorySettings(Document):
- def validate(self):
- self.validate_submittable_doctypes()
- self.validate_date_fieldnames()
-
- def validate_submittable_doctypes(self):
- for entry in self.custom_doctypes:
- if not cint(frappe.db.get_value('DocType', entry.document_type, 'is_submittable')):
- msg = _('Row #{0}: Document Type {1} is not submittable.').format(
- entry.idx, frappe.bold(entry.document_type))
- msg += _('Patient Medical Record can only be created for submittable document types.')
- frappe.throw(msg)
-
- def validate_date_fieldnames(self):
- for entry in self.custom_doctypes:
- field = frappe.get_meta(entry.document_type).get_field(entry.date_fieldname)
- if not field:
- frappe.throw(_('Row #{0}: No such Field named {1} found in the Document Type {2}.').format(
- entry.idx, frappe.bold(entry.date_fieldname), frappe.bold(entry.document_type)))
-
- if field.fieldtype not in ['Date', 'Datetime']:
- frappe.throw(_('Row #{0}: Field {1} in Document Type {2} is not a Date / Datetime field.').format(
- entry.idx, frappe.bold(entry.date_fieldname), frappe.bold(entry.document_type)))
-
- @frappe.whitelist()
- def get_doctype_fields(self, document_type, fields):
- multicheck_fields = []
- doc_fields = frappe.get_meta(document_type).fields
-
- for field in doc_fields:
- if field.fieldtype not in frappe.model.no_value_fields or \
- field.fieldtype in frappe.model.table_fields and not field.hidden:
- multicheck_fields.append({
- 'label': field.label,
- 'value': field.fieldname,
- 'checked': 1 if field.fieldname in fields else 0
- })
-
- return multicheck_fields
-
- @frappe.whitelist()
- def get_date_field_for_dt(self, document_type):
- meta = frappe.get_meta(document_type)
- date_fields = meta.get('fields', {
- 'fieldtype': ['in', ['Date', 'Datetime']]
- })
-
- if date_fields:
- return date_fields[0].get('fieldname')
-
-def create_medical_record(doc, method=None):
- medical_record_required = validate_medical_record_required(doc)
- if not medical_record_required:
- return
-
- if frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name }):
- return
-
- subject = set_subject_field(doc)
- date_field = get_date_field(doc.doctype)
- medical_record = frappe.new_doc('Patient Medical Record')
- medical_record.patient = doc.patient
- medical_record.subject = subject
- medical_record.status = 'Open'
- medical_record.communication_date = doc.get(date_field)
- medical_record.reference_doctype = doc.doctype
- medical_record.reference_name = doc.name
- medical_record.reference_owner = doc.owner
- medical_record.save(ignore_permissions=True)
-
-
-def update_medical_record(doc, method=None):
- medical_record_required = validate_medical_record_required(doc)
- if not medical_record_required:
- return
-
- medical_record_id = frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name })
-
- if medical_record_id:
- subject = set_subject_field(doc)
- frappe.db.set_value('Patient Medical Record', medical_record_id[0][0], 'subject', subject)
- else:
- create_medical_record(doc)
-
-
-def delete_medical_record(doc, method=None):
- medical_record_required = validate_medical_record_required(doc)
- if not medical_record_required:
- return
-
- record = frappe.db.exists('Patient Medical Record', { 'reference_name': doc.name })
- if record:
- frappe.delete_doc('Patient Medical Record', record, force=1)
-
-
-def set_subject_field(doc):
- from frappe.utils.formatters import format_value
-
- meta = frappe.get_meta(doc.doctype)
- subject = ''
- patient_history_fields = get_patient_history_fields(doc)
-
- for entry in patient_history_fields:
- fieldname = entry.get('fieldname')
- if entry.get('fieldtype') == 'Table' and doc.get(fieldname):
- formatted_value = get_formatted_value_for_table_field(doc.get(fieldname), meta.get_field(fieldname))
- subject += frappe.bold(_(entry.get('label')) + ':') + '
' + cstr(formatted_value) + '
'
-
- else:
- if doc.get(fieldname):
- formatted_value = format_value(doc.get(fieldname), meta.get_field(fieldname), doc)
- subject += frappe.bold(_(entry.get('label')) + ':') + cstr(formatted_value) + '
'
-
- return subject
-
-
-def get_date_field(doctype):
- dt = get_patient_history_config_dt(doctype)
-
- return frappe.db.get_value(dt, { 'document_type': doctype }, 'date_fieldname')
-
-
-def get_patient_history_fields(doc):
- dt = get_patient_history_config_dt(doc.doctype)
- patient_history_fields = frappe.db.get_value(dt, { 'document_type': doc.doctype }, 'selected_fields')
-
- if patient_history_fields:
- return json.loads(patient_history_fields)
-
-
-def get_formatted_value_for_table_field(items, df):
- child_meta = frappe.get_meta(df.options)
-
- table_head = ''
- table_row = ''
- html = ''
- create_head = True
- for item in items:
- table_row += '
'
- for cdf in child_meta.fields:
- if cdf.in_list_view:
- if create_head:
- table_head += '' + cdf.label + ' '
- if item.get(cdf.fieldname):
- table_row += '' + str(item.get(cdf.fieldname)) + ' '
- else:
- table_row += ' '
- create_head = False
- table_row += ' '
-
- html += "
" + table_head + table_row + "
"
-
- return html
-
-
-def get_patient_history_config_dt(doctype):
- if frappe.db.get_value('DocType', doctype, 'custom'):
- return 'Patient History Custom Document Type'
- else:
- return 'Patient History Standard Document Type'
-
-
-def validate_medical_record_required(doc):
- if frappe.flags.in_patch or frappe.flags.in_install or frappe.flags.in_setup_wizard \
- or get_module(doc) != 'Healthcare':
- return False
-
- if doc.doctype not in get_patient_history_doctypes():
- return False
-
- return True
-
-def get_module(doc):
- module = doc.meta.module
- if not module:
- module = frappe.db.get_value('DocType', doc.doctype, 'module')
-
- return module
diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
deleted file mode 100644
index c37a2adc368..00000000000
--- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import json
-import unittest
-
-import frappe
-from frappe.utils import getdate, strip_html
-
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient
-
-
-class TestPatientHistorySettings(unittest.TestCase):
- def setUp(self):
- dt = create_custom_doctype()
- settings = frappe.get_single("Patient History Settings")
- settings.append("custom_doctypes", {
- "document_type": dt.name,
- "date_fieldname": "date",
- "selected_fields": json.dumps([{
- "label": "Date",
- "fieldname": "date",
- "fieldtype": "Date"
- },
- {
- "label": "Rating",
- "fieldname": "rating",
- "fieldtype": "Rating"
- },
- {
- "label": "Feedback",
- "fieldname": "feedback",
- "fieldtype": "Small Text"
- }])
- })
- settings.save()
-
- def test_custom_doctype_medical_record(self):
- # tests for medical record creation of standard doctypes in test_patient_medical_record.py
- patient = create_patient()
- doc = create_doc(patient)
- # check for medical record
- medical_rec = frappe.db.exists("Patient Medical Record", {"status": "Open", "reference_name": doc.name})
- self.assertTrue(medical_rec)
-
- medical_rec = frappe.get_doc("Patient Medical Record", medical_rec)
- expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format(
- frappe.utils.format_date(getdate()))
- self.assertEqual(strip_html(medical_rec.subject), expected_subject)
- self.assertEqual(medical_rec.patient, patient)
- self.assertEqual(medical_rec.communication_date, getdate())
-
-
-def create_custom_doctype():
- if not frappe.db.exists("DocType", "Test Patient Feedback"):
- doc = frappe.get_doc({
- "doctype": "DocType",
- "module": "Healthcare",
- "custom": 1,
- "is_submittable": 1,
- "fields": [{
- "label": "Date",
- "fieldname": "date",
- "fieldtype": "Date"
- },
- {
- "label": "Patient",
- "fieldname": "patient",
- "fieldtype": "Link",
- "options": "Patient"
- },
- {
- "label": "Rating",
- "fieldname": "rating",
- "fieldtype": "Rating"
- },
- {
- "label": "Feedback",
- "fieldname": "feedback",
- "fieldtype": "Small Text"
- }],
- "permissions": [{
- "role": "System Manager",
- "read": 1
- }],
- "name": "Test Patient Feedback",
- })
- doc.insert()
- return doc
- else:
- return frappe.get_doc("DocType", "Test Patient Feedback")
-
-
-def create_doc(patient):
- doc = frappe.get_doc({
- "doctype": "Test Patient Feedback",
- "patient": patient,
- "date": getdate(),
- "rating": 3,
- "feedback": "Test Patient History Settings"
- }).insert()
- doc.submit()
-
- return doc
diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json
deleted file mode 100644
index b43099c4ea9..00000000000
--- a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "actions": [],
- "creation": "2020-11-25 13:39:36.014814",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "document_type",
- "date_fieldname",
- "add_edit_fields",
- "selected_fields"
- ],
- "fields": [
- {
- "fieldname": "document_type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Document Type",
- "options": "DocType",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "selected_fields",
- "fieldtype": "Code",
- "label": "Selected Fields",
- "read_only": 1
- },
- {
- "fieldname": "add_edit_fields",
- "fieldtype": "Button",
- "in_list_view": 1,
- "label": "Add / Edit Fields"
- },
- {
- "fieldname": "date_fieldname",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Date Fieldname",
- "read_only": 1,
- "reqd": 1
- }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2020-11-30 13:54:56.773325",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient History Standard Document Type",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py b/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
deleted file mode 100644
index b7dd09bc10c..00000000000
--- a/erpnext/healthcare/doctype/patient_history_standard_document_type/patient_history_standard_document_type.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class PatientHistoryStandardDocumentType(Document):
- pass
diff --git a/erpnext/healthcare/doctype/patient_medical_record/__init__.py b/erpnext/healthcare/doctype/patient_medical_record/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js
deleted file mode 100644
index 93ff70e6437..00000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2016, ESS LLP and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Patient Medical Record', {
-});
diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json
deleted file mode 100644
index ed82355f33a..00000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json
+++ /dev/null
@@ -1,155 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "allow_import": 1,
- "autoname": "naming_series:",
- "beta": 1,
- "creation": "2016-06-09 11:30:44.972056",
- "doctype": "DocType",
- "document_type": "Setup",
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "patient",
- "status",
- "column_break_2",
- "attach",
- "section_break_4",
- "subject",
- "section_break_8",
- "communication_date",
- "reference_doctype",
- "reference_name",
- "column_break_9",
- "reference_owner",
- "user"
- ],
- "fields": [
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "HLC-PMR-.YYYY.-",
- "print_hide": 1,
- "report_hide": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "label": "Patient",
- "options": "Patient",
- "search_index": 1
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "attach",
- "fieldtype": "Attach",
- "label": "Attach Medical Record"
- },
- {
- "fieldname": "section_break_4",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "subject",
- "fieldtype": "Text Editor",
- "ignore_xss_filter": 1,
- "label": "Subject"
- },
- {
- "fieldname": "status",
- "fieldtype": "Select",
- "label": "Status",
- "options": "Open\nClose",
- "read_only": 1
- },
- {
- "default": "Today",
- "fieldname": "communication_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Datetime",
- "read_only": 1
- },
- {
- "fieldname": "reference_doctype",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Reference DocType",
- "options": "DocType",
- "read_only": 1,
- "search_index": 1
- },
- {
- "fieldname": "reference_name",
- "fieldtype": "Dynamic Link",
- "in_list_view": 1,
- "label": "Reference Name",
- "options": "reference_doctype",
- "read_only": 1,
- "search_index": 1
- },
- {
- "fetch_from": "reference_name.owner",
- "fieldname": "reference_owner",
- "fieldtype": "Data",
- "label": "Reference Owner",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1
- },
- {
- "default": "__user",
- "fieldname": "user",
- "fieldtype": "Link",
- "label": "User",
- "options": "User",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1
- },
- {
- "fieldname": "column_break_9",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_8",
- "fieldtype": "Section Break"
- }
- ],
- "in_create": 1,
- "links": [],
- "modified": "2020-04-29 12:26:57.679402",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Medical Record",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient, subject, communication_date, reference_doctype, reference_name",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1,
- "track_seen": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py
deleted file mode 100644
index ac2cffa3e89..00000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe.model.document import Document
-
-
-class PatientMedicalRecord(Document):
- def after_insert(self):
- if self.reference_doctype == "Patient Medical Record" :
- frappe.db.set_value("Patient Medical Record", self.name, "reference_name", self.name)
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
deleted file mode 100644
index 099146c7ee7..00000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-import frappe
-from frappe.utils import nowdate
-
-from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
- create_appointment,
- create_encounter,
- create_healthcare_docs,
- create_medical_department,
-)
-
-
-class TestPatientMedicalRecord(unittest.TestCase):
- def setUp(self):
- frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
- frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- make_pos_profile()
-
- def test_medical_record(self):
- patient, practitioner = create_healthcare_docs()
- medical_department = create_medical_department()
- appointment = create_appointment(patient, practitioner, nowdate(), invoice=1)
- encounter = create_encounter(appointment)
-
- # check for encounter
- medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': encounter.name})
- self.assertTrue(medical_rec)
-
- vital_signs = create_vital_signs(appointment)
- # check for vital signs
- medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': vital_signs.name})
- self.assertTrue(medical_rec)
-
- appointment = create_appointment(patient, practitioner, nowdate(), invoice=1, procedure_template=1)
- procedure = create_procedure(appointment)
- procedure.start_procedure()
- procedure.complete_procedure()
- # check for clinical procedure
- medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': procedure.name})
- self.assertTrue(medical_rec)
-
- template = create_lab_test_template(medical_department)
- lab_test = create_lab_test(template.name, patient)
- # check for lab test
- medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': lab_test.name})
- self.assertTrue(medical_rec)
-
-
-def create_procedure(appointment):
- if appointment:
- procedure = frappe.new_doc('Clinical Procedure')
- procedure.procedure_template = appointment.procedure_template
- procedure.appointment = appointment.name
- procedure.patient = appointment.patient
- procedure.practitioner = appointment.practitioner
- procedure.medical_department = appointment.department
- procedure.start_dt = appointment.appointment_date
- procedure.start_time = appointment.appointment_time
- procedure.save()
- procedure.submit()
- return procedure
-
-def create_vital_signs(appointment):
- vital_signs = frappe.new_doc('Vital Signs')
- vital_signs.patient = appointment.patient
- vital_signs.signs_date = appointment.appointment_date
- vital_signs.signs_time = appointment.appointment_time
- vital_signs.temperature = 38.5
- vital_signs.save()
- vital_signs.submit()
- return vital_signs
-
-def create_lab_test_template(medical_department):
- if frappe.db.exists('Lab Test Template', 'Blood Test'):
- return frappe.get_doc('Lab Test Template', 'Blood Test')
-
- template = frappe.new_doc('Lab Test Template')
- template.lab_test_name = 'Blood Test'
- template.lab_test_code = 'Blood Test'
- template.lab_test_group = 'Services'
- template.department = medical_department
- template.is_billable = 1
- template.lab_test_rate = 2000
- template.save()
- return template
-
-def create_lab_test(template, patient):
- lab_test = frappe.new_doc('Lab Test')
- lab_test.patient = patient
- lab_test.patient_sex = frappe.db.get_value('Patient', patient, 'sex')
- lab_test.template = template
- lab_test.save()
- lab_test.submit()
- return lab_test
diff --git a/erpnext/healthcare/doctype/patient_relation/__init__.py b/erpnext/healthcare/doctype/patient_relation/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.json b/erpnext/healthcare/doctype/patient_relation/patient_relation.json
deleted file mode 100644
index 376f7f76d66..00000000000
--- a/erpnext/healthcare/doctype/patient_relation/patient_relation.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "beta": 1,
- "creation": "2017-04-26 15:40:11.561855",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "patient",
- "relation",
- "description"
- ],
- "fields": [
- {
- "fieldname": "relation",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Relation",
- "options": "\nFather\nMother\nSpouse\nSiblings\nFamily\nOther",
- "search_index": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1
- },
- {
- "fieldname": "description",
- "fieldtype": "Small Text",
- "ignore_xss_filter": 1,
- "label": "Description"
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-01-29 12:45:40.081899",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Relation",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "restrict_to_domain": "Healthcare",
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.py b/erpnext/healthcare/doctype/patient_relation/patient_relation.py
deleted file mode 100644
index 17bc20940d6..00000000000
--- a/erpnext/healthcare/doctype/patient_relation/patient_relation.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class PatientRelation(Document):
- pass
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/__init__.py b/erpnext/healthcare/doctype/practitioner_schedule/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js
deleted file mode 100644
index 7cb7c4b65e6..00000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Practitioner Schedule', {
- refresh: function(frm) {
- cur_frm.fields_dict["time_slots"].grid.wrapper.find('.grid-add-row').hide();
- cur_frm.fields_dict["time_slots"].grid.add_custom_button(__('Add Time Slots'), () => {
- let d = new frappe.ui.Dialog({
- fields: [
- {fieldname: 'days', label: __('Select Days'), fieldtype: 'MultiSelect',
- options:[
- {value:'Sunday', label:__('Sunday')},
- {value:'Monday', label:__('Monday')},
- {value:'Tuesday', label:__('Tuesday')},
- {value:'Wednesday', label:__('Wednesday')},
- {value:'Thursday', label:__('Thursday')},
- {value:'Friday', label:__('Friday')},
- {value:'Saturday', label:__('Saturday')},
- ], reqd: 1},
- {fieldname: 'from_time', label: __('From'), fieldtype: 'Time',
- 'default': '09:00:00', reqd: 1},
- {fieldname: 'to_time', label: __('To'), fieldtype: 'Time',
- 'default': '12:00:00', reqd: 1},
- {fieldname: 'duration', label: __('Appointment Duration (mins)'),
- fieldtype:'Int', 'default': 15, reqd: 1},
- ],
- primary_action_label: __('Add Timeslots'),
- primary_action: () => {
- let values = d.get_values();
- if (values) {
- let slot_added = false;
- values.days.split(',').forEach(function(day){
- day = $.trim(day);
- if (['Sunday', 'Monday', 'Tuesday', 'Wednesday',
- 'Thursday', 'Friday', 'Saturday'].includes(day)){
- add_slots(day);
- }
- });
-
- function check_overlap_or_add_slot(week_day, cur_time, end_time, add_slots_to_child){
- let overlap = false;
- while (cur_time < end_time) {
- let add_to_child = true;
- let to_time = cur_time.clone().add(values.duration, 'minutes');
- if (to_time <= end_time) {
- if (frm.doc.time_slots){
- frm.doc.time_slots.forEach(function(slot) {
- if (slot.day == week_day){
- let slot_from_moment = moment(slot.from_time, 'HH:mm:ss');
- let slot_to_moment = moment(slot.to_time, 'HH:mm:ss');
- if (cur_time.isSame(slot_from_moment) || cur_time.isBetween(slot_from_moment, slot_to_moment) ||
- to_time.isSame(slot_to_moment) || to_time.isBetween(slot_from_moment, slot_to_moment)) {
- overlap = true;
- if (add_slots_to_child) {
- frappe.show_alert({
- message:__('Time slot skiped, the slot {0} to {1} overlap exisiting slot {2} to {3}',
- [cur_time.format('HH:mm:ss'), to_time.format('HH:mm:ss'), slot.from_time, slot.to_time]),
- indicator:'orange'
- });
- add_to_child = false;
- }
- }
- }
- });
- }
- // add a new timeslot
- if (add_to_child && add_slots_to_child) {
- frm.add_child('time_slots', {
- from_time: cur_time.format('HH:mm:ss'),
- to_time: to_time.format('HH:mm:ss'),
- day: week_day
- });
- slot_added = true;
- }
- }
- cur_time = to_time;
- }
- return overlap;
- }
-
- function add_slots(week_day) {
- let cur_time = moment(values.from_time, 'HH:mm:ss');
- let end_time = moment(values.to_time, 'HH:mm:ss');
- if (check_overlap_or_add_slot(week_day, cur_time, end_time, false)) {
- frappe.confirm(__('Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?', [week_day]),
- function() {
- // if Yes
- check_overlap_or_add_slot(week_day, cur_time, end_time, true);
- },
- function() {
- // if No
- frappe.show_alert({
- message: __('Slots for {0} are not added to the schedule', [week_day]),
- indicator: 'red'
- });
- }
- );
- } else {
- check_overlap_or_add_slot(week_day, cur_time, end_time, true);
- }
- }
-
- frm.refresh_field('time_slots');
-
- if (slot_added) {
- frappe.show_alert({
- message: __('Time slots added'),
- indicator: 'green'
- });
- }
- }
- },
- });
- d.show();
- });
- }
-});
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json
deleted file mode 100644
index a21825ea8e7..00000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "actions": [],
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:schedule_name",
- "beta": 1,
- "creation": "2017-05-03 17:28:03.926787",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "disabled",
- "schedule_details_section",
- "schedule_name",
- "time_slots"
- ],
- "fields": [
- {
- "fieldname": "schedule_name",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Schedule Name",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "time_slots",
- "fieldtype": "Table",
- "label": "Time Slots",
- "options": "Healthcare Schedule Time Slot"
- },
- {
- "default": "0",
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled",
- "print_hide": 1
- },
- {
- "fieldname": "schedule_details_section",
- "fieldtype": "Section Break",
- "label": "Schedule Details"
- }
- ],
- "links": [],
- "modified": "2020-09-18 17:26:09.703215",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Practitioner Schedule",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py
deleted file mode 100644
index 7fa31e5fb67..00000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class PractitionerSchedule(Document):
- def autoname(self):
- self.name = self.schedule_name
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py
deleted file mode 100644
index 1ecaa47248a..00000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-
-class TestPractitionerSchedule(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/__init__.py b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json
deleted file mode 100644
index 4c283aaf1e4..00000000000
--- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.json
+++ /dev/null
@@ -1,110 +0,0 @@
-{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 1,
- "creation": "2017-11-16 12:19:17.163786",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "schedule",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Schedule",
- "length": 0,
- "no_copy": 0,
- "options": "Practitioner Schedule",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "service_unit",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Service Unit",
- "length": 0,
- "no_copy": 0,
- "options": "Healthcare Service Unit",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-11-04 03:33:07.936958",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Practitioner Service Unit Schedule",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py b/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py
deleted file mode 100644
index 4eba1fbf6b4..00000000000
--- a/erpnext/healthcare/doctype/practitioner_service_unit_schedule/practitioner_service_unit_schedule.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class PractitionerServiceUnitSchedule(Document):
- pass
diff --git a/erpnext/healthcare/doctype/prescription_dosage/__init__.py b/erpnext/healthcare/doctype/prescription_dosage/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js
deleted file mode 100644
index 94b444cbaa2..00000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Prescription Dosage', {
-});
diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json
deleted file mode 100644
index 9fb0dbc13ca..00000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json
+++ /dev/null
@@ -1,145 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:dosage",
- "beta": 1,
- "creation": "2016-09-16 15:49:25.327610",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "dosage",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 1,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Dosage",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "dosage_strength",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "options": "Dosage Strength",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-10-05 11:20:47.558464",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Prescription Dosage",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- },
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "search_fields": "dosage",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py
deleted file mode 100644
index 19f9b70bb61..00000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class PrescriptionDosage(Document):
- pass
diff --git a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py
deleted file mode 100644
index cabfd35e23d..00000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-
-class TestPrescriptionDosage(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/prescription_duration/__init__.py b/erpnext/healthcare/doctype/prescription_duration/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js
deleted file mode 100644
index dd5887c9296..00000000000
--- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Prescription Duration', {
-});
diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json
deleted file mode 100644
index c4f6c5f10da..00000000000
--- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.json
+++ /dev/null
@@ -1,145 +0,0 @@
-{
- "allow_copy": 1,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "",
- "beta": 1,
- "creation": "2016-09-16 15:50:28.895789",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "number",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Number",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "period",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Period",
- "length": 0,
- "no_copy": 0,
- "options": "Hour\nDay\nWeek\nMonth",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-08-31 13:42:51.325725",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Prescription Duration",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- },
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "search_fields": "",
- "show_name_in_global_search": 0,
- "sort_field": "",
- "sort_order": "ASC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py
deleted file mode 100644
index 988276da748..00000000000
--- a/erpnext/healthcare/doctype/prescription_duration/prescription_duration.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-from frappe.utils import cstr
-
-
-class PrescriptionDuration(Document):
- def autoname(self):
- self.name = " ".join(filter(None,
- [cstr(self.get(f)).strip() for f in ["number", "period"]]))
- def get_days(self):
- days = 0
- duration = self
- if(duration.period == 'Day'):
- days = duration.number
- if(duration.period == 'Hour'):
- days = (duration.number)/24
- if(duration.period == 'Week'):
- days = (duration.number*7)
- if(duration.period == 'Month'):
- days = (duration.number*30)
- return days
- def get_weeks(self):
- weeks = 0
- duration = self
- if(duration.period == 'Day'):
- weeks = (duration.number)/7
- #if(duration.period == 'Hour'):
- # weeks = (duration.number)/x
- if(duration.period == 'Week'):
- weeks = duration.number
- if(duration.period == 'Month'):
- weeks = duration.number*4
- return weeks
- def get_months(self):
- months = 0
- duration = self
- if(duration.period == 'Day'):
- months = (duration.number)/30
- #if(duration.period == 'Hour'):
- # months = (duration.number)/x
- if(duration.period == 'Week'):
- months = (duration.number)/4
- if(duration.period == 'Month'):
- months = duration.number
- return months
- def get_hours(self):
- hours = 0
- duration = self
- if(duration.period == 'Day'):
- hours = (duration.number*24)
- if(duration.period == 'Hour'):
- hours = duration.number
- if(duration.period == 'Week'):
- hours = (duration.number*24)*7
- if(duration.period == 'Month'):
- hours = (duration.number*24)*30
- return hours
- def get_minutes(self):
- minutes = 0
- duration = self
- if(duration.period == 'Day'):
- minutes = (duration.number*1440)
- if(duration.period == 'Hour'):
- minutes = (duration.number*60)
- if(duration.period == 'Week'):
- minutes = (duration.number*10080)
- if(duration.period == 'Month'):
- minutes = (duration.number*43800)
- return minutes
diff --git a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py
deleted file mode 100644
index 197bb3e7fb9..00000000000
--- a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-
-class TestPrescriptionDuration(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/procedure_prescription/__init__.py b/erpnext/healthcare/doctype/procedure_prescription/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json
deleted file mode 100644
index e4c01d79c10..00000000000
--- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json
+++ /dev/null
@@ -1,99 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "beta": 1,
- "creation": "2017-11-17 15:52:48.324157",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "procedure",
- "procedure_name",
- "department",
- "practitioner",
- "date",
- "comments",
- "appointment_booked",
- "procedure_created",
- "invoiced"
- ],
- "fields": [
- {
- "fieldname": "procedure",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Clinical Procedure",
- "options": "Clinical Procedure Template",
- "reqd": 1
- },
- {
- "fetch_from": "procedure.template",
- "fieldname": "procedure_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Procedure Name"
- },
- {
- "fetch_from": "procedure.medical_department",
- "fieldname": "department",
- "fieldtype": "Link",
- "label": "Department",
- "options": "Medical Department"
- },
- {
- "fieldname": "practitioner",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Referring Practitioner",
- "options": "Healthcare Practitioner"
- },
- {
- "fieldname": "date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Date"
- },
- {
- "fieldname": "comments",
- "fieldtype": "Data",
- "label": "Comments"
- },
- {
- "default": "0",
- "fieldname": "appointment_booked",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Appointment Booked",
- "search_index": 1
- },
- {
- "default": "0",
- "fieldname": "procedure_created",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Procedure Created",
- "no_copy": 1,
- "search_index": 1
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "label": "Invoiced",
- "read_only": 1,
- "search_index": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-02-26 15:42:33.988081",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Procedure Prescription",
- "owner": "Administrator",
- "permissions": [],
- "restrict_to_domain": "Healthcare",
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py
deleted file mode 100644
index f4d29fa6a30..00000000000
--- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class ProcedurePrescription(Document):
- pass
diff --git a/erpnext/healthcare/doctype/sample_collection/__init__.py b/erpnext/healthcare/doctype/sample_collection/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.js b/erpnext/healthcare/doctype/sample_collection/sample_collection.js
deleted file mode 100644
index ddf8285bc6d..00000000000
--- a/erpnext/healthcare/doctype/sample_collection/sample_collection.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2016, ESS and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Sample Collection', {
- refresh: function(frm) {
- if (frappe.defaults.get_default('create_sample_collection_for_lab_test')) {
- frm.add_custom_button(__('View Lab Tests'), function() {
- frappe.route_options = {'sample': frm.doc.name};
- frappe.set_route('List', 'Lab Test');
- });
- }
- }
-});
-
-frappe.ui.form.on('Sample Collection', 'patient', function(frm) {
- if(frm.doc.patient){
- frappe.call({
- 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
- args: {
- patient: frm.doc.patient
- },
- callback: function (data) {
- var age = null;
- if (data.message.dob){
- age = calculate_age(data.message.dob);
- }
- frappe.model.set_value(frm.doctype,frm.docname, 'patient_age', age);
- frappe.model.set_value(frm.doctype,frm.docname, 'patient_sex', data.message.sex);
- }
- });
- }
-});
-
-var calculate_age = function(birth) {
- var ageMS = Date.parse(Date()) - Date.parse(birth);
- var age = new Date();
- age.setTime(ageMS);
- var years = age.getFullYear() - 1970;
- return `${years} ${__('Years(s)')} ${age.getMonth()} ${__('Month(s)')} ${age.getDate()} ${__('Day(s)')}`;
-};
diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.json b/erpnext/healthcare/doctype/sample_collection/sample_collection.json
deleted file mode 100644
index 83383e34457..00000000000
--- a/erpnext/healthcare/doctype/sample_collection/sample_collection.json
+++ /dev/null
@@ -1,256 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "allow_import": 1,
- "autoname": "naming_series:",
- "beta": 1,
- "creation": "2016-04-05 15:58:18.076977",
- "doctype": "DocType",
- "document_type": "Document",
- "engine": "InnoDB",
- "field_order": [
- "patient_details_section",
- "naming_series",
- "patient",
- "patient_name",
- "patient_age",
- "patient_sex",
- "column_break_4",
- "inpatient_record",
- "company",
- "invoiced",
- "section_break_6",
- "sample",
- "sample_uom",
- "sample_qty",
- "column_break_10",
- "collected_by",
- "collected_time",
- "num_print",
- "section_break_15",
- "sample_details",
- "amended_from"
- ],
- "fields": [
- {
- "fetch_from": "patient.inpatient_record",
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Inpatient Record",
- "options": "Inpatient Record",
- "read_only": 1
- },
- {
- "bold": 1,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Series",
- "no_copy": 1,
- "options": "HLC-SC-.YYYY.-",
- "print_hide": 1,
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Invoiced",
- "no_copy": 1,
- "read_only": 1,
- "search_index": 1
- },
- {
- "fetch_from": "inpatient_record.patient",
- "fieldname": "patient",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "ignore_user_permissions": 1,
- "in_standard_filter": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1,
- "search_index": 1
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hide_days": 1,
- "hide_seconds": 1
- },
- {
- "fieldname": "patient_age",
- "fieldtype": "Data",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Age",
- "read_only": 1
- },
- {
- "fetch_from": "patient.sex",
- "fieldname": "patient_sex",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Gender",
- "options": "Gender",
- "read_only": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "options": "Company"
- },
- {
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Sample Details"
- },
- {
- "fieldname": "sample",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Sample",
- "options": "Lab Test Sample",
- "reqd": 1,
- "search_index": 1
- },
- {
- "fetch_from": "sample.sample_uom",
- "fieldname": "sample_uom",
- "fieldtype": "Data",
- "hide_days": 1,
- "hide_seconds": 1,
- "in_list_view": 1,
- "label": "UOM",
- "read_only": 1
- },
- {
- "fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hide_days": 1,
- "hide_seconds": 1
- },
- {
- "fieldname": "collected_by",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "ignore_user_permissions": 1,
- "label": "Collected By",
- "options": "User"
- },
- {
- "fieldname": "collected_time",
- "fieldtype": "Datetime",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Collected On"
- },
- {
- "allow_on_submit": 1,
- "default": "1",
- "description": "Number of prints required for labelling the samples",
- "fieldname": "num_print",
- "fieldtype": "Int",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "No. of prints",
- "print_hide": 1,
- "report_hide": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hide_days": 1,
- "hide_seconds": 1,
- "label": "Amended From",
- "no_copy": 1,
- "options": "Sample Collection",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "section_break_15",
- "fieldtype": "Section Break",
- "hide_days": 1,
- "hide_seconds": 1
- },
- {
- "default": "0",
- "fieldname": "sample_qty",
- "fieldtype": "Float",
- "hide_days": 1,
- "hide_seconds": 1,
- "in_list_view": 1,
- "label": "Quantity"
- },
- {
- "fieldname": "sample_details",
- "fieldtype": "Long Text",
- "hide_days": 1,
- "hide_seconds": 1,
- "ignore_xss_filter": 1,
- "label": "Collection Details"
- },
- {
- "fieldname": "patient_details_section",
- "fieldtype": "Section Break",
- "label": "Patient Details"
- },
- {
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2020-07-30 16:53:13.076104",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Sample Collection",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Laboratory User",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient, sample",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1,
- "track_seen": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.py b/erpnext/healthcare/doctype/sample_collection/sample_collection.py
deleted file mode 100644
index 7de6ac08ca1..00000000000
--- a/erpnext/healthcare/doctype/sample_collection/sample_collection.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from frappe.utils import flt
-
-
-class SampleCollection(Document):
- def validate(self):
- if flt(self.sample_qty) <= 0:
- frappe.throw(_('Sample Quantity cannot be negative or 0'), title=_('Invalid Quantity'))
diff --git a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py b/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py
deleted file mode 100644
index 0b16173dd53..00000000000
--- a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-# test_records = frappe.get_test_records('Sample Collection')
-
-class TestSampleCollection(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/sensitivity/__init__.py b/erpnext/healthcare/doctype/sensitivity/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.js b/erpnext/healthcare/doctype/sensitivity/sensitivity.js
deleted file mode 100644
index f9c9002fe6d..00000000000
--- a/erpnext/healthcare/doctype/sensitivity/sensitivity.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2016, ESS LLP and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Sensitivity', {
-});
diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.json b/erpnext/healthcare/doctype/sensitivity/sensitivity.json
deleted file mode 100644
index eddfda90566..00000000000
--- a/erpnext/healthcare/doctype/sensitivity/sensitivity.json
+++ /dev/null
@@ -1,115 +0,0 @@
-{
- "allow_copy": 1,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:sensitivity",
- "beta": 1,
- "creation": "2016-02-23 11:12:54.623249",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sensitivity",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 1,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Sensitivity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-10-05 11:19:12.110308",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Sensitivity",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Laboratory User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- },
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "search_fields": "sensitivity",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "sensitivity",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.py b/erpnext/healthcare/doctype/sensitivity/sensitivity.py
deleted file mode 100644
index f61781d3f86..00000000000
--- a/erpnext/healthcare/doctype/sensitivity/sensitivity.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class Sensitivity(Document):
- pass
diff --git a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py
deleted file mode 100644
index c772c72faf0..00000000000
--- a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-# test_records = frappe.get_test_records('Sensitivity')
-
-class TestSensitivity(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/__init__.py b/erpnext/healthcare/doctype/sensitivity_test_result/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json
deleted file mode 100644
index 768c17710fe..00000000000
--- a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
- "allow_copy": 1,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 1,
- "creation": "2016-02-22 15:18:01.769903",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "antibiotic",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Antibiotic",
- "length": 0,
- "no_copy": 0,
- "options": "Antibiotic",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "antibiotic_sensitivity",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Sensitivity",
- "length": 0,
- "no_copy": 0,
- "options": "Sensitivity",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-10-05 11:08:06.327972",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Sensitivity Test Result",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Healthcare",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py b/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py
deleted file mode 100644
index 53f7acc4af0..00000000000
--- a/erpnext/healthcare/doctype/sensitivity_test_result/sensitivity_test_result.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-from frappe.model.document import Document
-
-
-class SensitivityTestResult(Document):
- pass
diff --git a/erpnext/healthcare/doctype/therapy_plan/__init__.py b/erpnext/healthcare/doctype/therapy_plan/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
deleted file mode 100644
index 4f96f6a7066..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-import frappe
-from frappe.utils import flt, getdate, nowdate
-
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
- create_appointment,
- create_healthcare_docs,
- create_medical_department,
- create_patient,
-)
-from erpnext.healthcare.doctype.therapy_plan.therapy_plan import (
- make_sales_invoice,
- make_therapy_session,
-)
-from erpnext.healthcare.doctype.therapy_type.test_therapy_type import create_therapy_type
-
-
-class TestTherapyPlan(unittest.TestCase):
- def test_creation_on_encounter_submission(self):
- patient, practitioner = create_healthcare_docs()
- medical_department = create_medical_department()
- encounter = create_encounter(patient, medical_department, practitioner)
- self.assertTrue(frappe.db.exists('Therapy Plan', encounter.therapy_plan))
-
- def test_status(self):
- plan = create_therapy_plan()
- self.assertEqual(plan.status, 'Not Started')
-
- session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
- frappe.get_doc(session).submit()
- self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
-
- session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
- frappe.get_doc(session).submit()
- self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
-
- patient, practitioner = create_healthcare_docs()
- appointment = create_appointment(patient, practitioner, nowdate())
-
- session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
- session = frappe.get_doc(session)
- session.submit()
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')
- session.cancel()
- self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
-
- def test_therapy_plan_from_template(self):
- patient = create_patient()
- template = create_therapy_plan_template()
- # check linked item
- self.assertTrue(frappe.db.exists('Therapy Plan Template', {'linked_item': 'Complete Rehab'}))
-
- plan = create_therapy_plan(template)
- # invoice
- si = make_sales_invoice(plan.name, patient, '_Test Company', template)
- si.save()
-
- therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
- self.assertEqual(si.items[0].amount, therapy_plan_template_amt)
-
-
-def create_therapy_plan(template=None):
- patient = create_patient()
- therapy_type = create_therapy_type()
- plan = frappe.new_doc('Therapy Plan')
- plan.patient = patient
- plan.start_date = getdate()
-
- if template:
- plan.therapy_plan_template = template
- plan = plan.set_therapy_details_from_template()
- else:
- plan.append('therapy_plan_details', {
- 'therapy_type': therapy_type.name,
- 'no_of_sessions': 2
- })
-
- plan.save()
- return plan
-
-def create_encounter(patient, medical_department, practitioner):
- encounter = frappe.new_doc('Patient Encounter')
- encounter.patient = patient
- encounter.practitioner = practitioner
- encounter.medical_department = medical_department
- therapy_type = create_therapy_type()
- encounter.append('therapies', {
- 'therapy_type': therapy_type.name,
- 'no_of_sessions': 2
- })
- encounter.save()
- encounter.submit()
- return encounter
-
-def create_therapy_plan_template():
- template_name = frappe.db.exists('Therapy Plan Template', 'Complete Rehab')
- if not template_name:
- therapy_type = create_therapy_type()
- template = frappe.new_doc('Therapy Plan Template')
- template.plan_name = template.item_code = template.item_name = 'Complete Rehab'
- template.item_group = 'Services'
- rate = frappe.db.get_value('Therapy Type', therapy_type.name, 'rate')
- template.append('therapy_types', {
- 'therapy_type': therapy_type.name,
- 'no_of_sessions': 2,
- 'rate': rate,
- 'amount': 2 * flt(rate)
- })
- template.save()
- template_name = template.name
-
- return template_name
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
deleted file mode 100644
index 42e231dc662..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Therapy Plan', {
- setup: function(frm) {
- frm.get_field('therapy_plan_details').grid.editable_fields = [
- {fieldname: 'therapy_type', columns: 6},
- {fieldname: 'no_of_sessions', columns: 2},
- {fieldname: 'sessions_completed', columns: 2}
- ];
- },
-
- refresh: function(frm) {
- if (!frm.doc.__islocal) {
- frm.trigger('show_progress_for_therapies');
- if (frm.doc.status != 'Completed') {
- let therapy_types = (frm.doc.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
- const fields = [{
- fieldtype: 'Link',
- label: __('Therapy Type'),
- fieldname: 'therapy_type',
- options: 'Therapy Type',
- reqd: 1,
- get_query: function() {
- return {
- filters: { 'therapy_type': ['in', therapy_types]}
- };
- }
- }];
-
- frm.add_custom_button(__('Therapy Session'), function() {
- frappe.prompt(fields, data => {
- frappe.call({
- method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_therapy_session',
- args: {
- therapy_plan: frm.doc.name,
- patient: frm.doc.patient,
- therapy_type: data.therapy_type,
- company: frm.doc.company
- },
- freeze: true,
- callback: function(r) {
- if (r.message) {
- frappe.model.sync(r.message);
- frappe.set_route('Form', r.message.doctype, r.message.name);
- }
- }
- });
- }, __('Select Therapy Type'), __('Create'));
- }, __('Create'));
- }
-
- if (frm.doc.therapy_plan_template && !frm.doc.invoiced) {
- frm.add_custom_button(__('Sales Invoice'), function() {
- frm.trigger('make_sales_invoice');
- }, __('Create'));
- }
- }
-
- if (frm.doc.therapy_plan_template) {
- frm.fields_dict.therapy_plan_details.grid.update_docfield_property(
- 'therapy_type', 'read_only', 1
- );
- frm.fields_dict.therapy_plan_details.grid.update_docfield_property(
- 'no_of_sessions', 'read_only', 1
- );
- }
- },
-
- make_sales_invoice: function(frm) {
- frappe.call({
- args: {
- 'reference_name': frm.doc.name,
- 'patient': frm.doc.patient,
- 'company': frm.doc.company,
- 'therapy_plan_template': frm.doc.therapy_plan_template
- },
- method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_sales_invoice',
- callback: function(r) {
- var doclist = frappe.model.sync(r.message);
- frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
- }
- });
- },
-
- therapy_plan_template: function(frm) {
- if (frm.doc.therapy_plan_template) {
- frappe.call({
- method: 'set_therapy_details_from_template',
- doc: frm.doc,
- freeze: true,
- freeze_message: __('Fetching Template Details'),
- callback: function() {
- refresh_field('therapy_plan_details');
- }
- });
- }
- },
-
- show_progress_for_therapies: function(frm) {
- let bars = [];
- let message = '';
-
- // completed sessions
- let title = __('{0} sessions completed', [frm.doc.total_sessions_completed]);
- if (frm.doc.total_sessions_completed === 1) {
- title = __('{0} session completed', [frm.doc.total_sessions_completed]);
- }
- title += __(' out of {0}', [frm.doc.total_sessions]);
-
- bars.push({
- 'title': title,
- 'width': (frm.doc.total_sessions_completed / frm.doc.total_sessions * 100) + '%',
- 'progress_class': 'progress-bar-success'
- });
- if (bars[0].width == '0%') {
- bars[0].width = '0.5%';
- }
- message = title;
- frm.dashboard.add_progress(__('Status'), bars, message);
- },
-});
-
-frappe.ui.form.on('Therapy Plan Detail', {
- no_of_sessions: function(frm) {
- let total = 0;
- $.each(frm.doc.therapy_plan_details, function(_i, e) {
- total += e.no_of_sessions;
- });
- frm.set_value('total_sessions', total);
- refresh_field('total_sessions');
- }
-});
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
deleted file mode 100644
index c03e9de3320..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "actions": [],
- "autoname": "naming_series:",
- "creation": "2020-03-29 20:56:49.758602",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "patient",
- "patient_name",
- "invoiced",
- "column_break_4",
- "company",
- "status",
- "start_date",
- "section_break_3",
- "therapy_plan_template",
- "therapy_plan_details",
- "title",
- "section_break_9",
- "total_sessions",
- "column_break_11",
- "total_sessions_completed"
- ],
- "fields": [
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1
- },
- {
- "fieldname": "start_date",
- "fieldtype": "Date",
- "in_list_view": 1,
- "label": "Start Date",
- "reqd": 1
- },
- {
- "fieldname": "section_break_3",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "therapy_plan_details",
- "fieldtype": "Table",
- "label": "Therapy Plan Details",
- "options": "Therapy Plan Detail",
- "read_only_depends_on": "therapy_plan_template",
- "reqd": 1
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Naming Series",
- "options": "HLC-THP-.YYYY.-"
- },
- {
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- },
- {
- "default": "{patient_name}",
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Title",
- "no_copy": 1
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_9",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "total_sessions",
- "fieldtype": "Int",
- "label": "Total Sessions",
- "read_only": 1
- },
- {
- "fieldname": "column_break_11",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "total_sessions_completed",
- "fieldtype": "Int",
- "label": "Total Sessions Completed",
- "read_only": 1
- },
- {
- "fieldname": "status",
- "fieldtype": "Select",
- "label": "Status",
- "options": "Not Started\nIn Progress\nCompleted\nCancelled",
- "read_only": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Company",
- "options": "Company",
- "reqd": 1
- },
- {
- "fieldname": "therapy_plan_template",
- "fieldtype": "Link",
- "label": "Therapy Plan Template",
- "options": "Therapy Plan Template",
- "set_only_once": 1
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "label": "Invoiced",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- }
- ],
- "links": [],
- "modified": "2020-11-04 18:13:13.564999",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Plan",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "search_fields": "patient",
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
deleted file mode 100644
index 6d63f391895..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe.model.document import Document
-from frappe.utils import flt, today
-
-
-class TherapyPlan(Document):
- def validate(self):
- self.set_totals()
- self.set_status()
-
- def set_status(self):
- if not self.total_sessions_completed:
- self.status = 'Not Started'
- else:
- if self.total_sessions_completed < self.total_sessions:
- self.status = 'In Progress'
- elif self.total_sessions_completed == self.total_sessions:
- self.status = 'Completed'
-
- def set_totals(self):
- total_sessions = 0
- total_sessions_completed = 0
- for entry in self.therapy_plan_details:
- if entry.no_of_sessions:
- total_sessions += entry.no_of_sessions
- if entry.sessions_completed:
- total_sessions_completed += entry.sessions_completed
-
- self.db_set('total_sessions', total_sessions)
- self.db_set('total_sessions_completed', total_sessions_completed)
-
- @frappe.whitelist()
- def set_therapy_details_from_template(self):
- # Add therapy types in the child table
- self.set('therapy_plan_details', [])
- therapy_plan_template = frappe.get_doc('Therapy Plan Template', self.therapy_plan_template)
-
- for data in therapy_plan_template.therapy_types:
- self.append('therapy_plan_details', {
- 'therapy_type': data.therapy_type,
- 'no_of_sessions': data.no_of_sessions
- })
- return self
-
-
-@frappe.whitelist()
-def make_therapy_session(therapy_plan, patient, therapy_type, company, appointment=None):
- therapy_type = frappe.get_doc('Therapy Type', therapy_type)
-
- therapy_session = frappe.new_doc('Therapy Session')
- therapy_session.therapy_plan = therapy_plan
- therapy_session.company = company
- therapy_session.patient = patient
- therapy_session.therapy_type = therapy_type.name
- therapy_session.duration = therapy_type.default_duration
- therapy_session.rate = therapy_type.rate
- therapy_session.exercises = therapy_type.exercises
- therapy_session.appointment = appointment
-
- if frappe.flags.in_test:
- therapy_session.start_date = today()
- return therapy_session.as_dict()
-
-
-@frappe.whitelist()
-def make_sales_invoice(reference_name, patient, company, therapy_plan_template):
- from erpnext.stock.get_item_details import get_item_details
- si = frappe.new_doc('Sales Invoice')
- si.company = company
- si.patient = patient
- si.customer = frappe.db.get_value('Patient', patient, 'customer')
-
- item = frappe.db.get_value('Therapy Plan Template', therapy_plan_template, 'linked_item')
- price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0]
- args = {
- 'doctype': 'Sales Invoice',
- 'item_code': item,
- 'company': company,
- 'customer': si.customer,
- 'selling_price_list': price_list,
- 'price_list_currency': price_list_currency,
- 'plc_conversion_rate': 1.0,
- 'conversion_rate': 1.0
- }
-
- item_line = si.append('items', {})
- item_details = get_item_details(args)
- item_line.item_code = item
- item_line.qty = 1
- item_line.rate = item_details.price_list_rate
- item_line.amount = flt(item_line.rate) * flt(item_line.qty)
- item_line.reference_dt = 'Therapy Plan'
- item_line.reference_dn = reference_name
- item_line.description = item_details.description
-
- si.set_missing_values(for_validate = True)
- return si
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
deleted file mode 100644
index 25c8df1d6b7..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'therapy_plan',
- 'non_standard_fieldnames': {
- 'Sales Invoice': 'reference_dn'
- },
- 'transactions': [
- {
- 'label': _('Therapy Sessions'),
- 'items': ['Therapy Session']
- },
- {
- 'label': _('Billing'),
- 'items': ['Sales Invoice']
- }
- ],
- 'disable_create_buttons': ['Sales Invoice']
- }
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js
deleted file mode 100644
index 63967aff33b..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_list.js
+++ /dev/null
@@ -1,11 +0,0 @@
-frappe.listview_settings['Therapy Plan'] = {
- get_indicator: function(doc) {
- var colors = {
- 'Completed': 'green',
- 'In Progress': 'orange',
- 'Not Started': 'red',
- 'Cancelled': 'grey'
- };
- return [__(doc.status), colors[doc.status], 'status,=,' + doc.status];
- }
-};
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/__init__.py b/erpnext/healthcare/doctype/therapy_plan_detail/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
deleted file mode 100644
index 77f08af07d9..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "actions": [],
- "creation": "2020-03-29 20:52:57.068731",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "therapy_type",
- "no_of_sessions",
- "sessions_completed"
- ],
- "fields": [
- {
- "fieldname": "therapy_type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Therapy Type",
- "options": "Therapy Type",
- "reqd": 1
- },
- {
- "fieldname": "no_of_sessions",
- "fieldtype": "Int",
- "in_list_view": 1,
- "label": "No of Sessions"
- },
- {
- "default": "0",
- "depends_on": "eval:doc.parenttype=='Therapy Plan';",
- "fieldname": "sessions_completed",
- "fieldtype": "Int",
- "label": "Sessions Completed",
- "no_copy": 1,
- "read_only": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-11-04 18:15:52.173450",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Plan Detail",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py
deleted file mode 100644
index 1842fc2197b..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class TherapyPlanDetail(Document):
- pass
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
deleted file mode 100644
index cd3d5686bc0..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-# import frappe
-import unittest
-
-
-class TestTherapyPlanTemplate(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js
deleted file mode 100644
index 86de1928e23..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Therapy Plan Template', {
- refresh: function(frm) {
- frm.set_query('therapy_type', 'therapy_types', () => {
- return {
- filters: {
- 'is_billable': 1
- }
- };
- });
- },
-
- set_totals: function(frm) {
- let total_sessions = 0;
- let total_amount = 0.0;
- frm.doc.therapy_types.forEach((d) => {
- if (d.no_of_sessions) total_sessions += cint(d.no_of_sessions);
- if (d.amount) total_amount += flt(d.amount);
- });
- frm.set_value('total_sessions', total_sessions);
- frm.set_value('total_amount', total_amount);
- frm.refresh_fields();
- }
-});
-
-frappe.ui.form.on('Therapy Plan Template Detail', {
- therapy_type: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- frappe.call('frappe.client.get', {
- doctype: 'Therapy Type',
- name: row.therapy_type
- }).then((res) => {
- row.rate = res.message.rate;
- if (!row.no_of_sessions)
- row.no_of_sessions = 1;
- row.amount = flt(row.rate) * cint(row.no_of_sessions);
- frm.refresh_field('therapy_types');
- frm.trigger('set_totals');
- });
- },
-
- no_of_sessions: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- row.amount = flt(row.rate) * cint(row.no_of_sessions);
- frm.refresh_field('therapy_types');
- frm.trigger('set_totals');
- },
-
- rate: function(frm, cdt, cdn) {
- let row = locals[cdt][cdn];
- row.amount = flt(row.rate) * cint(row.no_of_sessions);
- frm.refresh_field('therapy_types');
- frm.trigger('set_totals');
- }
-});
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json
deleted file mode 100644
index 48fc896257b..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json
+++ /dev/null
@@ -1,132 +0,0 @@
-{
- "actions": [],
- "autoname": "field:plan_name",
- "creation": "2020-09-22 17:51:38.861055",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "plan_name",
- "linked_item_details_section",
- "item_code",
- "item_name",
- "item_group",
- "column_break_6",
- "description",
- "linked_item",
- "therapy_types_section",
- "therapy_types",
- "section_break_11",
- "total_sessions",
- "column_break_13",
- "total_amount"
- ],
- "fields": [
- {
- "fieldname": "plan_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Plan Name",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "therapy_types_section",
- "fieldtype": "Section Break",
- "label": "Therapy Types"
- },
- {
- "fieldname": "therapy_types",
- "fieldtype": "Table",
- "label": "Therapy Types",
- "options": "Therapy Plan Template Detail",
- "reqd": 1
- },
- {
- "fieldname": "linked_item",
- "fieldtype": "Link",
- "label": "Linked Item",
- "options": "Item",
- "read_only": 1
- },
- {
- "fieldname": "linked_item_details_section",
- "fieldtype": "Section Break",
- "label": "Linked Item Details"
- },
- {
- "fieldname": "item_code",
- "fieldtype": "Data",
- "label": "Item Code",
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "item_name",
- "fieldtype": "Data",
- "label": "Item Name",
- "reqd": 1
- },
- {
- "fieldname": "item_group",
- "fieldtype": "Link",
- "label": "Item Group",
- "options": "Item Group",
- "reqd": 1
- },
- {
- "fieldname": "column_break_6",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "description",
- "fieldtype": "Small Text",
- "label": "Item Description"
- },
- {
- "fieldname": "total_amount",
- "fieldtype": "Currency",
- "label": "Total Amount",
- "read_only": 1
- },
- {
- "fieldname": "section_break_11",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "total_sessions",
- "fieldtype": "Int",
- "label": "Total Sessions",
- "read_only": 1
- },
- {
- "fieldname": "column_break_13",
- "fieldtype": "Column Break"
- }
- ],
- "index_web_pages_for_search": 1,
- "links": [],
- "modified": "2020-10-08 00:56:58.062105",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Plan Template",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
deleted file mode 100644
index f5512be207f..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe.model.document import Document
-from frappe.utils import cint, flt
-
-from erpnext.healthcare.doctype.therapy_type.therapy_type import make_item_price
-
-
-class TherapyPlanTemplate(Document):
- def after_insert(self):
- self.create_item_from_template()
-
- def validate(self):
- self.set_totals()
-
- def on_update(self):
- doc_before_save = self.get_doc_before_save()
- if not doc_before_save: return
- if doc_before_save.item_name != self.item_name or doc_before_save.item_group != self.item_group \
- or doc_before_save.description != self.description:
- self.update_item()
-
- if doc_before_save.therapy_types != self.therapy_types:
- self.update_item_price()
-
- def set_totals(self):
- total_sessions = 0
- total_amount = 0
-
- for entry in self.therapy_types:
- total_sessions += cint(entry.no_of_sessions)
- total_amount += flt(entry.amount)
-
- self.total_sessions = total_sessions
- self.total_amount = total_amount
-
- def create_item_from_template(self):
- uom = frappe.db.exists('UOM', 'Nos') or frappe.db.get_single_value('Stock Settings', 'stock_uom')
-
- item = frappe.get_doc({
- 'doctype': 'Item',
- 'item_code': self.item_code,
- 'item_name': self.item_name,
- 'item_group': self.item_group,
- 'description': self.description,
- 'is_sales_item': 1,
- 'is_service_item': 1,
- 'is_purchase_item': 0,
- 'is_stock_item': 0,
- 'show_in_website': 0,
- 'is_pro_applicable': 0,
- 'stock_uom': uom
- }).insert(ignore_permissions=True, ignore_mandatory=True)
-
- make_item_price(item.name, self.total_amount)
- self.db_set('linked_item', item.name)
-
- def update_item(self):
- item_doc = frappe.get_doc('Item', {'item_code': self.linked_item})
- item_doc.item_name = self.item_name
- item_doc.item_group = self.item_group
- item_doc.description = self.description
- item_doc.ignore_mandatory = True
- item_doc.save(ignore_permissions=True)
-
- def update_item_price(self):
- item_price = frappe.get_doc('Item Price', {'item_code': self.linked_item})
- item_price.item_name = self.item_name
- item_price.price_list_rate = self.total_amount
- item_price.ignore_mandatory = True
- item_price.save(ignore_permissions=True)
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
deleted file mode 100644
index def5c482d15..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'therapy_plan_template',
- 'transactions': [
- {
- 'label': _('Therapy Plans'),
- 'items': ['Therapy Plan']
- }
- ]
- }
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json
deleted file mode 100644
index 5553a118f87..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "actions": [],
- "creation": "2020-10-07 23:04:44.373381",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "therapy_type",
- "no_of_sessions",
- "rate",
- "amount"
- ],
- "fields": [
- {
- "fieldname": "therapy_type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Therapy Type",
- "options": "Therapy Type",
- "reqd": 1
- },
- {
- "fieldname": "no_of_sessions",
- "fieldtype": "Int",
- "in_list_view": 1,
- "label": "No of Sessions"
- },
- {
- "fieldname": "rate",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Rate"
- },
- {
- "fieldname": "amount",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Amount",
- "read_only": 1
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2020-10-07 23:46:54.296322",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Plan Template Detail",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
deleted file mode 100644
index 104c1bf28bd..00000000000
--- a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-# import frappe
-from frappe.model.document import Document
-
-
-class TherapyPlanTemplateDetail(Document):
- pass
diff --git a/erpnext/healthcare/doctype/therapy_session/__init__.py b/erpnext/healthcare/doctype/therapy_session/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
deleted file mode 100644
index fbfa774c91c..00000000000
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Therapy Session', {
- setup: function(frm) {
- frm.get_field('exercises').grid.editable_fields = [
- {fieldname: 'exercise_type', columns: 7},
- {fieldname: 'counts_target', columns: 1},
- {fieldname: 'counts_completed', columns: 1},
- {fieldname: 'assistance_level', columns: 1}
- ];
-
- frm.set_query('service_unit', function() {
- return {
- filters: {
- 'is_group': false,
- 'allow_appointments': true,
- 'company': frm.doc.company
- }
- };
- });
-
- frm.set_query('appointment', function() {
-
- return {
- filters: {
- 'status': ['in', ['Open', 'Scheduled']]
- }
- };
- });
- },
-
- refresh: function(frm) {
- if (frm.doc.therapy_plan) {
- frm.trigger('filter_therapy_types');
- }
-
- if (!frm.doc.__islocal) {
- frm.dashboard.add_indicator(__('Counts Targeted: {0}', [frm.doc.total_counts_targeted]), 'blue');
- frm.dashboard.add_indicator(__('Counts Completed: {0}', [frm.doc.total_counts_completed]),
- (frm.doc.total_counts_completed < frm.doc.total_counts_targeted) ? 'orange' : 'green');
- }
-
- if (frm.doc.docstatus === 1) {
- frm.add_custom_button(__('Patient Assessment'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.healthcare.doctype.patient_assessment.patient_assessment.create_patient_assessment',
- frm: frm,
- })
- }, 'Create');
-
- frappe.db.get_value('Therapy Plan', {'name': frm.doc.therapy_plan}, 'therapy_plan_template', (r) => {
- if (r && !r.therapy_plan_template) {
- frm.add_custom_button(__('Sales Invoice'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.healthcare.doctype.therapy_session.therapy_session.invoice_therapy_session',
- frm: frm,
- });
- }, 'Create');
- }
- });
- }
- },
-
- therapy_plan: function(frm) {
- if (frm.doc.therapy_plan) {
- frm.trigger('filter_therapy_types');
- }
- },
-
- filter_therapy_types: function(frm) {
- frappe.call({
- 'method': 'frappe.client.get',
- args: {
- doctype: 'Therapy Plan',
- name: frm.doc.therapy_plan
- },
- callback: function(data) {
- let therapy_types = (data.message.therapy_plan_details || []).map(function(d){ return d.therapy_type; });
- frm.set_query('therapy_type', function() {
- return {
- filters: { 'therapy_type': ['in', therapy_types]}
- };
- });
- }
- });
- },
-
- patient: function(frm) {
- if (frm.doc.patient) {
- frappe.call({
- 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
- args: {
- patient: frm.doc.patient
- },
- callback: function (data) {
- let age = '';
- if (data.message.dob) {
- age = calculate_age(data.message.dob);
- } else if (data.message.age) {
- age = data.message.age;
- if (data.message.age_as_on) {
- age = __('{0} as on {1}', [age, data.message.age_as_on]);
- }
- }
- frm.set_value('patient_age', age);
- frm.set_value('gender', data.message.sex);
- frm.set_value('patient_name', data.message.patient_name);
- }
- });
- } else {
- frm.set_value('patient_age', '');
- frm.set_value('gender', '');
- frm.set_value('patient_name', '');
- }
- },
-
- appointment: function(frm) {
- if (frm.doc.appointment) {
- frappe.call({
- 'method': 'frappe.client.get',
- args: {
- doctype: 'Patient Appointment',
- name: frm.doc.appointment
- },
- callback: function(data) {
- let values = {
- 'patient':data.message.patient,
- 'therapy_type': data.message.therapy_type,
- 'therapy_plan': data.message.therapy_plan,
- 'practitioner': data.message.practitioner,
- 'department': data.message.department,
- 'start_date': data.message.appointment_date,
- 'start_time': data.message.appointment_time,
- 'service_unit': data.message.service_unit,
- 'company': data.message.company,
- 'duration': data.message.duration
- };
- frm.set_value(values);
- }
- });
- }
- },
-
- therapy_type: function(frm) {
- if (frm.doc.therapy_type) {
- frappe.call({
- 'method': 'frappe.client.get',
- args: {
- doctype: 'Therapy Type',
- name: frm.doc.therapy_type
- },
- callback: function(data) {
- frm.set_value('duration', data.message.default_duration);
- frm.set_value('rate', data.message.rate);
- frm.set_value('service_unit', data.message.healthcare_service_unit);
- frm.set_value('department', data.message.medical_department);
- frm.doc.exercises = [];
- $.each(data.message.exercises, function(_i, e) {
- let exercise = frm.add_child('exercises');
- exercise.exercise_type = e.exercise_type;
- exercise.difficulty_level = e.difficulty_level;
- exercise.counts_target = e.counts_target;
- exercise.assistance_level = e.assistance_level;
- });
- refresh_field('exercises');
- }
- });
- }
- }
-});
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
deleted file mode 100644
index 0bb2b0ef2ae..00000000000
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json
+++ /dev/null
@@ -1,264 +0,0 @@
-{
- "actions": [],
- "autoname": "naming_series:",
- "creation": "2020-03-11 08:57:40.669857",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "appointment",
- "patient",
- "patient_name",
- "patient_age",
- "gender",
- "column_break_5",
- "company",
- "therapy_plan",
- "therapy_type",
- "practitioner",
- "department",
- "details_section",
- "medical_code",
- "duration",
- "rate",
- "location",
- "column_break_12",
- "service_unit",
- "start_date",
- "start_time",
- "invoiced",
- "exercises_section",
- "exercises",
- "section_break_23",
- "total_counts_targeted",
- "column_break_25",
- "total_counts_completed",
- "amended_from"
- ],
- "fields": [
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "HLC-THP-.YYYY.-"
- },
- {
- "fieldname": "appointment",
- "fieldtype": "Link",
- "label": "Appointment",
- "options": "Patient Appointment",
- "set_only_once": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1
- },
- {
- "fetch_from": "patient.sex",
- "fieldname": "gender",
- "fieldtype": "Link",
- "label": "Gender",
- "options": "Gender",
- "read_only": 1
- },
- {
- "fieldname": "column_break_5",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "practitioner",
- "fieldtype": "Link",
- "label": "Healthcare Practitioner",
- "options": "Healthcare Practitioner"
- },
- {
- "fieldname": "department",
- "fieldtype": "Link",
- "label": "Medical Department",
- "options": "Medical Department"
- },
- {
- "fieldname": "details_section",
- "fieldtype": "Section Break",
- "label": "Details"
- },
- {
- "fetch_from": "therapy_template.default_duration",
- "fieldname": "duration",
- "fieldtype": "Int",
- "label": "Duration",
- "reqd": 1
- },
- {
- "fieldname": "location",
- "fieldtype": "Select",
- "label": "Location",
- "options": "\nCenter\nHome\nTele"
- },
- {
- "fieldname": "column_break_12",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "therapy_template.rate",
- "fieldname": "rate",
- "fieldtype": "Currency",
- "label": "Rate"
- },
- {
- "fieldname": "exercises_section",
- "fieldtype": "Section Break",
- "label": "Exercises"
- },
- {
- "fieldname": "exercises",
- "fieldtype": "Table",
- "label": "Exercises",
- "options": "Exercise"
- },
- {
- "depends_on": "eval: doc.therapy_plan",
- "fieldname": "therapy_type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Therapy Type",
- "options": "Therapy Type",
- "reqd": 1
- },
- {
- "fieldname": "therapy_plan",
- "fieldtype": "Link",
- "label": "Therapy Plan",
- "options": "Therapy Plan",
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Therapy Session",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "service_unit",
- "fieldtype": "Link",
- "label": "Healthcare Service Unit",
- "options": "Healthcare Service Unit"
- },
- {
- "fieldname": "start_date",
- "fieldtype": "Date",
- "label": "Start Date",
- "reqd": 1
- },
- {
- "fieldname": "start_time",
- "fieldtype": "Time",
- "label": "Start Time"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "reqd": 1
- },
- {
- "default": "0",
- "fieldname": "invoiced",
- "fieldtype": "Check",
- "label": "Invoiced",
- "read_only": 1
- },
- {
- "fieldname": "patient_age",
- "fieldtype": "Data",
- "label": "Patient Age",
- "read_only": 1
- },
- {
- "fieldname": "total_counts_targeted",
- "fieldtype": "Int",
- "label": "Total Counts Targeted",
- "read_only": 1
- },
- {
- "fieldname": "total_counts_completed",
- "fieldtype": "Int",
- "label": "Total Counts Completed",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "fieldname": "section_break_23",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "column_break_25",
- "fieldtype": "Column Break"
- },
- {
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- },
- {
- "fetch_from": "therapy_type.medical_code",
- "fieldname": "medical_code",
- "fieldtype": "Link",
- "label": "Medical Code",
- "options": "Medical Code",
- "read_only": 1
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2020-11-04 18:14:25.999939",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Session",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "cancel": 1,
- "create": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "search_fields": "patient,appointment,therapy_plan,therapy_type",
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "patient",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
deleted file mode 100644
index 915e6e42f4c..00000000000
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import datetime
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, get_link_to_form, get_time, getdate
-
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import (
- get_income_account,
- get_receivable_account,
-)
-
-
-class TherapySession(Document):
- def validate(self):
- self.validate_duplicate()
- self.set_total_counts()
-
- def validate_duplicate(self):
- end_time = datetime.datetime.combine(getdate(self.start_date), get_time(self.start_time)) \
- + datetime.timedelta(minutes=flt(self.duration))
-
- overlaps = frappe.db.sql("""
- select
- name
- from
- `tabTherapy Session`
- where
- start_date=%s and name!=%s and docstatus!=2
- and (practitioner=%s or patient=%s) and
- ((start_time<%s and start_time + INTERVAL duration MINUTE>%s) or
- (start_time>%s and start_time<%s) or
- (start_time=%s))
- """, (self.start_date, self.name, self.practitioner, self.patient,
- self.start_time, end_time.time(), self.start_time, end_time.time(), self.start_time))
-
- if overlaps:
- overlapping_details = _('Therapy Session overlaps with {0}').format(get_link_to_form('Therapy Session', overlaps[0][0]))
- frappe.throw(overlapping_details, title=_('Therapy Sessions Overlapping'))
-
- def on_submit(self):
- self.update_sessions_count_in_therapy_plan()
-
- def on_update(self):
- if self.appointment:
- frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed')
-
- def on_cancel(self):
- if self.appointment:
- frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open')
-
- self.update_sessions_count_in_therapy_plan(on_cancel=True)
-
- def update_sessions_count_in_therapy_plan(self, on_cancel=False):
- therapy_plan = frappe.get_doc('Therapy Plan', self.therapy_plan)
- for entry in therapy_plan.therapy_plan_details:
- if entry.therapy_type == self.therapy_type:
- if on_cancel:
- entry.sessions_completed -= 1
- else:
- entry.sessions_completed += 1
- therapy_plan.save()
-
- def set_total_counts(self):
- target_total = 0
- counts_completed = 0
- for entry in self.exercises:
- if entry.counts_target:
- target_total += entry.counts_target
- if entry.counts_completed:
- counts_completed += entry.counts_completed
-
- self.db_set('total_counts_targeted', target_total)
- self.db_set('total_counts_completed', counts_completed)
-
-
-@frappe.whitelist()
-def create_therapy_session(source_name, target_doc=None):
- def set_missing_values(source, target):
- therapy_type = frappe.get_doc('Therapy Type', source.therapy_type)
- target.exercises = therapy_type.exercises
-
- doc = get_mapped_doc('Patient Appointment', source_name, {
- 'Patient Appointment': {
- 'doctype': 'Therapy Session',
- 'field_map': [
- ['appointment', 'name'],
- ['patient', 'patient'],
- ['patient_age', 'patient_age'],
- ['gender', 'patient_sex'],
- ['therapy_type', 'therapy_type'],
- ['therapy_plan', 'therapy_plan'],
- ['practitioner', 'practitioner'],
- ['department', 'department'],
- ['start_date', 'appointment_date'],
- ['start_time', 'appointment_time'],
- ['service_unit', 'service_unit'],
- ['company', 'company'],
- ['invoiced', 'invoiced']
- ]
- }
- }, target_doc, set_missing_values)
-
- return doc
-
-
-@frappe.whitelist()
-def invoice_therapy_session(source_name, target_doc=None):
- def set_missing_values(source, target):
- target.customer = frappe.db.get_value('Patient', source.patient, 'customer')
- target.due_date = getdate()
- target.debit_to = get_receivable_account(source.company)
- item = target.append('items', {})
- item = get_therapy_item(source, item)
- target.set_missing_values(for_validate=True)
-
- doc = get_mapped_doc('Therapy Session', source_name, {
- 'Therapy Session': {
- 'doctype': 'Sales Invoice',
- 'field_map': [
- ['patient', 'patient'],
- ['referring_practitioner', 'practitioner'],
- ['company', 'company'],
- ['due_date', 'start_date']
- ]
- }
- }, target_doc, set_missing_values)
-
- return doc
-
-
-def get_therapy_item(therapy, item):
- item.item_code = frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item')
- item.description = _('Therapy Session Charges: {0}').format(therapy.practitioner)
- item.income_account = get_income_account(therapy.practitioner, therapy.company)
- item.cost_center = frappe.get_cached_value('Company', therapy.company, 'cost_center')
- item.rate = therapy.rate
- item.amount = therapy.rate
- item.qty = 1
- item.reference_dt = 'Therapy Session'
- item.reference_dn = therapy.name
- return item
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py b/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py
deleted file mode 100644
index b8a37820ba0..00000000000
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session_dashboard.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from __future__ import unicode_literals
-
-from frappe import _
-
-
-def get_data():
- return {
- 'fieldname': 'therapy_session',
- 'transactions': [
- {
- 'label': _('Assessments'),
- 'items': ['Patient Assessment']
- }
- ]
- }
diff --git a/erpnext/healthcare/doctype/therapy_type/__init__.py b/erpnext/healthcare/doctype/therapy_type/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
deleted file mode 100644
index 23d542236b8..00000000000
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-import frappe
-
-
-class TestTherapyType(unittest.TestCase):
- def test_therapy_type_item(self):
- therapy_type = create_therapy_type()
- self.assertTrue(frappe.db.exists('Item', therapy_type.item))
-
- therapy_type.disabled = 1
- therapy_type.save()
- self.assertEqual(frappe.db.get_value('Item', therapy_type.item, 'disabled'), 1)
-
-def create_therapy_type():
- exercise = create_exercise_type()
- therapy_type = frappe.db.exists('Therapy Type', 'Basic Rehab')
- if not therapy_type:
- therapy_type = frappe.new_doc('Therapy Type')
- therapy_type.therapy_type = 'Basic Rehab'
- therapy_type.default_duration = 30
- therapy_type.is_billable = 1
- therapy_type.rate = 5000
- therapy_type.item_code = 'Basic Rehab'
- therapy_type.item_name = 'Basic Rehab'
- therapy_type.item_group = 'Services'
- therapy_type.append('exercises', {
- 'exercise_type': exercise.name,
- 'counts_target': 10,
- 'assistance_level': 'Passive'
- })
- therapy_type.save()
- else:
- therapy_type = frappe.get_doc('Therapy Type', therapy_type)
-
- return therapy_type
-
-def create_exercise_type():
- exercise_type = frappe.db.exists('Exercise Type', 'Sit to Stand')
- if not exercise_type:
- exercise_type = frappe.new_doc('Exercise Type')
- exercise_type.exercise_name = 'Sit to Stand'
- exercise_type.append('steps_table', {
- 'title': 'Step 1',
- 'description': 'Squat and Rise'
- })
- exercise_type.save()
- else:
- exercise_type = frappe.get_doc('Exercise Type', exercise_type)
-
- return exercise_type
diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.js b/erpnext/healthcare/doctype/therapy_type/therapy_type.js
deleted file mode 100644
index 6e155dc21f9..00000000000
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Therapy Type', {
- setup: function(frm) {
- frm.get_field('exercises').grid.editable_fields = [
- {fieldname: 'exercise_type', columns: 7},
- {fieldname: 'difficulty_level', columns: 1},
- {fieldname: 'counts_target', columns: 1},
- {fieldname: 'assistance_level', columns: 1}
- ];
- },
-
- refresh: function(frm) {
- if (!frm.doc.__islocal) {
- cur_frm.add_custom_button(__('Change Item Code'), function() {
- change_template_code(frm.doc);
- });
- }
- },
-
- therapy_type: function(frm) {
- if (!frm.doc.item_code)
- frm.set_value('item_code', frm.doc.therapy_type);
- if (!frm.doc.description)
- frm.set_value('description', frm.doc.therapy_type);
- mark_change_in_item(frm);
- },
-
- rate: function(frm) {
- mark_change_in_item(frm);
- },
-
- is_billable: function (frm) {
- mark_change_in_item(frm);
- },
-
- item_group: function(frm) {
- mark_change_in_item(frm);
- },
-
- description: function(frm) {
- mark_change_in_item(frm);
- },
-
- medical_department: function(frm) {
- mark_change_in_item(frm);
- },
-
- medical_code: function(frm) {
- frm.set_query("medical_code", function() {
- return {
- filters: {
- medical_code_standard: frm.doc.medical_code_standard
- }
- };
- });
- }
-});
-
-let mark_change_in_item = function(frm) {
- if (!frm.doc.__islocal) {
- frm.doc.change_in_item = 1;
- }
-};
-
-let change_template_code = function(doc) {
- let d = new frappe.ui.Dialog({
- title:__('Change Item Code'),
- fields:[
- {
- 'fieldtype': 'Data',
- 'label': 'Item Code',
- 'fieldname': 'item_code',
- reqd: 1
- }
- ],
- primary_action: function() {
- let values = d.get_values();
-
- if (values) {
- frappe.call({
- 'method': 'erpnext.healthcare.doctype.therapy_type.therapy_type.change_item_code_from_therapy',
- 'args': {item_code: values.item_code, doc: doc},
- callback: function () {
- cur_frm.reload_doc();
- frappe.show_alert({
- message: 'Item Code renamed successfully',
- indicator: 'green'
- });
- }
- });
- }
- d.hide();
- },
- primary_action_label: __('Change Item Code')
- });
- d.show();
-
- d.set_values({
- 'item_code': doc.item_code
- });
-};
diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.json b/erpnext/healthcare/doctype/therapy_type/therapy_type.json
deleted file mode 100644
index f365b1df032..00000000000
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.json
+++ /dev/null
@@ -1,234 +0,0 @@
-{
- "actions": [],
- "autoname": "field:therapy_type",
- "creation": "2020-03-29 20:48:31.715063",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "disabled",
- "section_break_2",
- "therapy_type",
- "default_duration",
- "medical_department",
- "column_break_3",
- "is_billable",
- "rate",
- "healthcare_service_unit",
- "item_details_section",
- "item",
- "item_code",
- "item_name",
- "item_group",
- "column_break_12",
- "description",
- "medical_coding_section",
- "medical_code_standard",
- "medical_code",
- "section_break_18",
- "therapy_for",
- "add_exercises",
- "section_break_6",
- "exercises",
- "change_in_item"
- ],
- "fields": [
- {
- "fieldname": "therapy_type",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Therapy Type",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "fieldname": "is_billable",
- "fieldtype": "Check",
- "label": "Is Billable"
- },
- {
- "depends_on": "eval:doc.is_billable;",
- "fieldname": "rate",
- "fieldtype": "Currency",
- "label": "Rate",
- "mandatory_depends_on": "eval:doc.is_billable;"
- },
- {
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "label": "Exercises"
- },
- {
- "fieldname": "exercises",
- "fieldtype": "Table",
- "label": "Exercises",
- "options": "Exercise"
- },
- {
- "fieldname": "default_duration",
- "fieldtype": "Int",
- "label": "Default Duration (In Minutes)"
- },
- {
- "default": "0",
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled"
- },
- {
- "fieldname": "item_details_section",
- "fieldtype": "Section Break",
- "label": "Item Details"
- },
- {
- "fieldname": "item",
- "fieldtype": "Link",
- "label": "Item",
- "options": "Item",
- "read_only": 1
- },
- {
- "fieldname": "item_code",
- "fieldtype": "Data",
- "label": "Item Code",
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "item_group",
- "fieldtype": "Link",
- "label": "Item Group",
- "options": "Item Group",
- "reqd": 1
- },
- {
- "fieldname": "item_name",
- "fieldtype": "Data",
- "label": "Item Name",
- "reqd": 1
- },
- {
- "fieldname": "column_break_12",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "description",
- "fieldtype": "Small Text",
- "label": "Description"
- },
- {
- "fieldname": "section_break_2",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "medical_department",
- "fieldtype": "Link",
- "label": "Medical Department",
- "options": "Medical Department"
- },
- {
- "default": "0",
- "fieldname": "change_in_item",
- "fieldtype": "Check",
- "hidden": 1,
- "label": "Change In Item",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1
- },
- {
- "fieldname": "therapy_for",
- "fieldtype": "Table MultiSelect",
- "label": "Therapy For",
- "options": "Body Part Link"
- },
- {
- "fieldname": "healthcare_service_unit",
- "fieldtype": "Link",
- "label": "Healthcare Service Unit",
- "options": "Healthcare Service Unit"
- },
- {
- "depends_on": "eval: doc.therapy_for",
- "fieldname": "add_exercises",
- "fieldtype": "Button",
- "label": "Add Exercises",
- "options": "add_exercises"
- },
- {
- "fieldname": "section_break_18",
- "fieldtype": "Section Break"
- },
- {
- "collapsible": 1,
- "fieldname": "medical_coding_section",
- "fieldtype": "Section Break",
- "label": "Medical Coding",
- "options": "Medical Coding"
- },
- {
- "fieldname": "medical_code_standard",
- "fieldtype": "Link",
- "label": "Medical Code Standard",
- "options": "Medical Code Standard"
- },
- {
- "depends_on": "medical_code_standard",
- "fieldname": "medical_code",
- "fieldtype": "Link",
- "label": "Medical Code",
- "options": "Medical Code"
- }
- ],
- "links": [],
- "modified": "2020-06-29 14:18:50.669951",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Therapy Type",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- },
- {
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.py b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
deleted file mode 100644
index 3517ef2c5ad..00000000000
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-from frappe.model.rename_doc import rename_doc
-from frappe.utils import cint
-
-
-class TherapyType(Document):
- def validate(self):
- self.enable_disable_item()
-
- def after_insert(self):
- create_item_from_therapy(self)
-
- def on_update(self):
- if self.change_in_item:
- self.update_item_and_item_price()
-
- def enable_disable_item(self):
- if self.is_billable:
- if self.disabled:
- frappe.db.set_value('Item', self.item, 'disabled', 1)
- else:
- frappe.db.set_value('Item', self.item, 'disabled', 0)
-
- def update_item_and_item_price(self):
- if self.is_billable and self.item:
- item_doc = frappe.get_doc('Item', {'item_code': self.item})
- item_doc.item_name = self.item_name
- item_doc.item_group = self.item_group
- item_doc.description = self.description
- item_doc.disabled = 0
- item_doc.ignore_mandatory = True
- item_doc.save(ignore_permissions=True)
-
- if self.rate:
- item_price = frappe.get_doc('Item Price', {'item_code': self.item})
- item_price.item_name = self.item_name
- item_price.price_list_rate = self.rate
- item_price.ignore_mandatory = True
- item_price.save()
-
- elif not self.is_billable and self.item:
- frappe.db.set_value('Item', self.item, 'disabled', 1)
-
- self.db_set('change_in_item', 0)
-
- @frappe.whitelist()
- def add_exercises(self):
- exercises = self.get_exercises_for_body_parts()
- last_idx = max([cint(d.idx) for d in self.get('exercises')] or [0,])
- for i, d in enumerate(exercises):
- ch = self.append('exercises', {})
- ch.exercise_type = d.parent
- ch.idx = last_idx + i + 1
-
- def get_exercises_for_body_parts(self):
- body_parts = [entry.body_part for entry in self.therapy_for]
-
- exercises = frappe.db.sql(
- """
- SELECT DISTINCT
- b.parent, e.name, e.difficulty_level
- FROM
- `tabExercise Type` e, `tabBody Part Link` b
- WHERE
- b.body_part IN %(body_parts)s AND b.parent=e.name
- """, {'body_parts': body_parts}, as_dict=1)
-
- return exercises
-
-
-def create_item_from_therapy(doc):
- disabled = doc.disabled
- if doc.is_billable and not doc.disabled:
- disabled = 0
-
- uom = frappe.db.exists('UOM', 'Unit') or frappe.db.get_single_value('Stock Settings', 'stock_uom')
-
- item = frappe.get_doc({
- 'doctype': 'Item',
- 'item_code': doc.item_code,
- 'item_name': doc.item_name,
- 'item_group': doc.item_group,
- 'description': doc.description,
- 'is_sales_item': 1,
- 'is_service_item': 1,
- 'is_purchase_item': 0,
- 'is_stock_item': 0,
- 'show_in_website': 0,
- 'is_pro_applicable': 0,
- 'disabled': disabled,
- 'stock_uom': uom
- }).insert(ignore_permissions=True, ignore_mandatory=True)
-
- make_item_price(item.name, doc.rate)
- doc.db_set('item', item.name)
-
-
-def make_item_price(item, item_price):
- price_list_name = frappe.db.get_value('Price List', {'selling': 1})
- frappe.get_doc({
- 'doctype': 'Item Price',
- 'price_list': price_list_name,
- 'item_code': item,
- 'price_list_rate': item_price
- }).insert(ignore_permissions=True, ignore_mandatory=True)
-
-@frappe.whitelist()
-def change_item_code_from_therapy(item_code, doc):
- doc = frappe._dict(json.loads(doc))
-
- if frappe.db.exists('Item', {'item_code': item_code}):
- frappe.throw(_('Item with Item Code {0} already exists').format(item_code))
- else:
- rename_doc('Item', doc.item, item_code, ignore_permissions=True)
- frappe.db.set_value('Therapy Type', doc.name, 'item_code', item_code)
- return
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
deleted file mode 100644
index d661b4304f6..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
- {
- "doctype": "Treatment Plan Template",
- "template_name": "Chemo",
- "patient_age_from": 21
- }
-]
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
deleted file mode 100644
index 986c3cb6e42..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Treatment Plan Template', {
- refresh: function (frm) {
- frm.set_query('type', 'items', function () {
- return {
- filters: {
- 'name': ['in', ['Lab Test Template', 'Clinical Procedure Template', 'Therapy Type']],
- }
- };
- });
- },
-});
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
deleted file mode 100644
index 85a312fb174..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
+++ /dev/null
@@ -1,189 +0,0 @@
-{
- "actions": [],
- "autoname": "field:template_name",
- "creation": "2021-06-10 10:14:17.901273",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "section_break_1",
- "template_name",
- "description",
- "practitioners",
- "disabled",
- "column_break_1",
- "medical_department",
- "goal",
- "order_group",
- "section_break_8",
- "patient_age_from",
- "complaints",
- "gender",
- "column_break_12",
- "patient_age_to",
- "diagnosis",
- "plan_items_section",
- "items",
- "drugs"
- ],
- "fields": [
- {
- "fieldname": "section_break_1",
- "fieldtype": "Section Break",
- "label": "Plan Details"
- },
- {
- "fieldname": "medical_department",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Medical Department",
- "options": "Medical Department"
- },
- {
- "fieldname": "description",
- "fieldtype": "Small Text",
- "label": "Description"
- },
- {
- "fieldname": "goal",
- "fieldtype": "Small Text",
- "label": "Goal"
- },
- {
- "fieldname": "practitioners",
- "fieldtype": "Table MultiSelect",
- "label": "Practitioners",
- "options": "Treatment Plan Template Practitioner"
- },
- {
- "fieldname": "order_group",
- "fieldtype": "Link",
- "label": "Order Group",
- "options": "Patient Encounter",
- "read_only": 1
- },
- {
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "label": "Plan Conditions"
- },
- {
- "fieldname": "template_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Template Name",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "patient_age_from",
- "fieldtype": "Int",
- "label": "Patient Age From",
- "non_negative": 1
- },
- {
- "fieldname": "column_break_12",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "patient_age_to",
- "fieldtype": "Int",
- "label": "Patient Age To",
- "non_negative": 1
- },
- {
- "fieldname": "gender",
- "fieldtype": "Link",
- "label": "Gender",
- "options": "Gender"
- },
- {
- "fieldname": "complaints",
- "fieldtype": "Table MultiSelect",
- "label": "Complaints",
- "options": "Patient Encounter Symptom"
- },
- {
- "fieldname": "diagnosis",
- "fieldtype": "Table MultiSelect",
- "label": "Diagnosis",
- "options": "Patient Encounter Diagnosis"
- },
- {
- "fieldname": "plan_items_section",
- "fieldtype": "Section Break",
- "label": "Plan Items"
- },
- {
- "fieldname": "items",
- "fieldtype": "Table",
- "label": "Items",
- "options": "Treatment Plan Template Item"
- },
- {
- "fieldname": "drugs",
- "fieldtype": "Table",
- "label": "Drugs",
- "options": "Drug Prescription"
- },
- {
- "default": "0",
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled"
- },
- {
- "fieldname": "column_break_1",
- "fieldtype": "Column Break"
- }
- ],
- "index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-08-18 02:41:58.354296",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Treatment Plan Template",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "write": 1
- },
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Healthcare Administrator",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "template_name",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
deleted file mode 100644
index dbe0e9ae5f4..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-
-
-class TreatmentPlanTemplate(Document):
- def validate(self):
- self.validate_age()
-
- def validate_age(self):
- if self.patient_age_from and self.patient_age_from < 0:
- frappe.throw(_('Patient Age From cannot be less than 0'))
- if self.patient_age_to and self.patient_age_to < 0:
- frappe.throw(_('Patient Age To cannot be less than 0'))
- if self.patient_age_to and self.patient_age_from and \
- self.patient_age_to < self.patient_age_from:
- frappe.throw(_('Patient Age To cannot be less than Patient Age From'))
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
deleted file mode 100644
index 7ab31dff791..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
+++ /dev/null
@@ -1,10 +0,0 @@
-frappe.listview_settings['Treatment Plan Template'] = {
- get_indicator: function(doc) {
- var colors = {
- 1: 'gray',
- 0: 'blue',
- };
- let label = doc.disabled == 1 ? 'Disabled' : 'Enabled';
- return [__(label), colors[doc.disabled], 'disable,=,' + doc.disabled];
- }
-};
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
deleted file mode 100644
index 20a9d6793a5..00000000000
--- a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "actions": [],
- "creation": "2021-06-10 11:47:29.194795",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "type",
- "template",
- "qty",
- "instructions"
- ],
- "fields": [
- {
- "fieldname": "type",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Type",
- "options": "DocType",
- "reqd": 1
- },
- {
- "fieldname": "template",
- "fieldtype": "Dynamic Link",
- "in_list_view": 1,
- "label": "Template",
- "options": "type",
- "reqd": 1
- },
- {
- "default": "1",
- "fieldname": "qty",
- "fieldtype": "Int",
- "label": "Qty"
- },
- {
- "fieldname": "instructions",
- "fieldtype": "Small Text",
- "in_list_view": 1,
- "label": "Instructions"
- }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-08-17 11:19:03.515441",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Treatment Plan Template Item",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/vital_signs/__init__.py b/erpnext/healthcare/doctype/vital_signs/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py
deleted file mode 100644
index 22b52fb4822..00000000000
--- a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-# test_records = frappe.get_test_records('Vital Signs')
-
-class TestVitalSigns(unittest.TestCase):
- pass
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.js b/erpnext/healthcare/doctype/vital_signs/vital_signs.js
deleted file mode 100644
index 78509e0323c..00000000000
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2016, ESS LLP and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Vital Signs', {
- height: function(frm) {
- if (frm.doc.height && frm.doc.weight) {
- calculate_bmi(frm);
- }
- },
-
- weight: function(frm) {
- if (frm.doc.height && frm.doc.weight) {
- calculate_bmi(frm);
- }
- },
-
- bp_systolic: function(frm) {
- if (frm.doc.bp_systolic && frm.doc.bp_diastolic) {
- set_bp(frm);
- }
- },
-
- bp_diastolic: function(frm) {
- if (frm.doc.bp_systolic && frm.doc.bp_diastolic) {
- set_bp(frm);
- }
- }
-});
-
-let calculate_bmi = function(frm){
- // Reference https://en.wikipedia.org/wiki/Body_mass_index
- // bmi = weight (in Kg) / height * height (in Meter)
- let bmi = (frm.doc.weight / (frm.doc.height * frm.doc.height)).toFixed(2);
- let bmi_note = null;
-
- if (bmi<18.5) {
- bmi_note = 'Underweight';
- } else if (bmi>=18.5 && bmi<25) {
- bmi_note = 'Normal';
- } else if (bmi>=25 && bmi<30) {
- bmi_note = 'Overweight';
- } else if (bmi>=30) {
- bmi_note = 'Obese';
- }
- frappe.model.set_value(frm.doctype,frm.docname, 'bmi', bmi);
- frappe.model.set_value(frm.doctype,frm.docname, 'nutrition_note', bmi_note);
-};
-
-let set_bp = function(frm){
- let bp = frm.doc.bp_systolic+ '/' + frm.doc.bp_diastolic + ' mmHg';
- frappe.model.set_value(frm.doctype,frm.docname, 'bp', bp);
-};
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.json b/erpnext/healthcare/doctype/vital_signs/vital_signs.json
deleted file mode 100644
index 15ab5047bc4..00000000000
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.json
+++ /dev/null
@@ -1,305 +0,0 @@
-{
- "actions": [],
- "allow_copy": 1,
- "allow_import": 1,
- "autoname": "naming_series:",
- "beta": 1,
- "creation": "2017-02-02 11:00:24.853005",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "title",
- "patient",
- "patient_name",
- "inpatient_record",
- "appointment",
- "encounter",
- "column_break_2",
- "company",
- "signs_date",
- "signs_time",
- "sb_vs",
- "temperature",
- "pulse",
- "respiratory_rate",
- "tongue",
- "abdomen",
- "column_break_8",
- "reflexes",
- "bp_systolic",
- "bp_diastolic",
- "bp",
- "vital_signs_note",
- "sb_nutrition_values",
- "height",
- "weight",
- "bmi",
- "column_break_14",
- "nutrition_note",
- "sb_references",
- "amended_from"
- ],
- "fields": [
- {
- "fetch_from": "patient.inpatient_record",
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "label": "Inpatient Record",
- "options": "Inpatient Record",
- "read_only": 1
- },
- {
- "fetch_from": "inpatient_record.patient",
- "fieldname": "patient",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Patient",
- "options": "Patient",
- "reqd": 1
- },
- {
- "fetch_from": "patient.patient_name",
- "fieldname": "patient_name",
- "fieldtype": "Data",
- "label": "Patient Name",
- "read_only": 1
- },
- {
- "fieldname": "appointment",
- "fieldtype": "Link",
- "in_filter": 1,
- "label": "Patient Appointment",
- "no_copy": 1,
- "options": "Patient Appointment",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "encounter",
- "fieldtype": "Link",
- "in_filter": 1,
- "label": "Patient Encounter",
- "no_copy": 1,
- "options": "Patient Encounter",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "default": "Today",
- "fieldname": "signs_date",
- "fieldtype": "Date",
- "label": "Date",
- "reqd": 1
- },
- {
- "fieldname": "signs_time",
- "fieldtype": "Time",
- "label": "Time",
- "reqd": 1
- },
- {
- "fieldname": "sb_vs",
- "fieldtype": "Section Break",
- "label": "Vital Signs"
- },
- {
- "description": "Presence of a fever (temp > 38.5 \u00b0C/101.3 \u00b0F or sustained temp > 38 \u00b0C/100.4 \u00b0F)",
- "fieldname": "temperature",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Body Temperature"
- },
- {
- "description": "Adults' pulse rate is anywhere between 50 and 80 beats per minute.",
- "fieldname": "pulse",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Heart Rate / Pulse"
- },
- {
- "description": "Normal reference range for an adult is 16\u201320 breaths/minute (RCP 2012)",
- "fieldname": "respiratory_rate",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Respiratory rate"
- },
- {
- "fieldname": "tongue",
- "fieldtype": "Select",
- "label": "Tongue",
- "options": "\nCoated\nVery Coated\nNormal\nFurry\nCuts"
- },
- {
- "fieldname": "abdomen",
- "fieldtype": "Select",
- "label": "Abdomen",
- "options": "\nNormal\nBloated\nFull\nFluid\nConstipated"
- },
- {
- "fieldname": "column_break_8",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "reflexes",
- "fieldtype": "Select",
- "label": "Reflexes",
- "options": "\nNormal\nHyper\nVery Hyper\nOne Sided"
- },
- {
- "fieldname": "bp_systolic",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Blood Pressure (systolic)"
- },
- {
- "fieldname": "bp_diastolic",
- "fieldtype": "Data",
- "ignore_xss_filter": 1,
- "in_list_view": 1,
- "label": "Blood Pressure (diastolic)"
- },
- {
- "description": "Normal resting blood pressure in an adult is approximately 120 mmHg systolic, and 80 mmHg diastolic, abbreviated \"120/80 mmHg\"",
- "fieldname": "bp",
- "fieldtype": "Data",
- "label": "Blood Pressure",
- "read_only": 1
- },
- {
- "fieldname": "vital_signs_note",
- "fieldtype": "Small Text",
- "ignore_xss_filter": 1,
- "label": "Notes"
- },
- {
- "fieldname": "sb_nutrition_values",
- "fieldtype": "Section Break",
- "label": "Nutrition Values"
- },
- {
- "fieldname": "height",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Height (In Meter)"
- },
- {
- "fieldname": "weight",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Weight (In Kilogram)"
- },
- {
- "default": "0.00",
- "fieldname": "bmi",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "BMI",
- "read_only": 1
- },
- {
- "fieldname": "column_break_14",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "nutrition_note",
- "fieldtype": "Small Text",
- "ignore_xss_filter": 1,
- "label": "Notes"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company"
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Vital Signs",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "sb_references",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "HLC-VTS-.YYYY.-",
- "reqd": 1
- },
- {
- "allow_on_submit": 1,
- "columns": 5,
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Title",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- }
- ],
- "is_submittable": 1,
- "links": [],
- "modified": "2020-05-17 22:23:24.632286",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Vital Signs",
- "owner": "Administrator",
- "permissions": [
- {
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Physician",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Nursing User",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "restrict_to_domain": "Healthcare",
- "search_fields": "patient, signs_date",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py
deleted file mode 100644
index 29dbeb470dd..00000000000
--- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _
-from frappe.model.document import Document
-
-
-class VitalSigns(Document):
- def validate(self):
- self.set_title()
-
- def set_title(self):
- self.title = _('{0} on {1}').format(self.patient_name or self.patient,
- frappe.utils.format_date(self.signs_date))[:100]
diff --git a/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json b/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json
deleted file mode 100644
index 2fea6682ed2..00000000000
--- a/erpnext/healthcare/healthcare_dashboard/healthcare/healthcare.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "cards": [
- {
- "card": "Total Patients"
- },
- {
- "card": "Total Patients Admitted"
- },
- {
- "card": "Open Appointments"
- },
- {
- "card": "Appointments to Bill"
- }
- ],
- "charts": [
- {
- "chart": "Patient Appointments",
- "width": "Full"
- },
- {
- "chart": "In-Patient Status",
- "width": "Half"
- },
- {
- "chart": "Clinical Procedures Status",
- "width": "Half"
- },
- {
- "chart": "Lab Tests",
- "width": "Half"
- },
- {
- "chart": "Clinical Procedures",
- "width": "Half"
- },
- {
- "chart": "Symptoms",
- "width": "Half"
- },
- {
- "chart": "Diagnoses",
- "width": "Half"
- },
- {
- "chart": "Department wise Patient Appointments",
- "width": "Full"
- }
- ],
- "creation": "2020-07-14 18:17:54.823311",
- "dashboard_name": "Healthcare",
- "docstatus": 0,
- "doctype": "Dashboard",
- "idx": 0,
- "is_default": 0,
- "is_standard": 1,
- "modified": "2020-07-22 15:36:34.220387",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Healthcare",
- "owner": "Administrator"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
deleted file mode 100644
index 0aa8f9a027e..00000000000
--- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "allow_roles": [
- {
- "role": "Healthcare Administrator"
- }
- ],
- "creation": "2020-05-19 10:32:43.025852",
- "docstatus": 0,
- "doctype": "Module Onboarding",
- "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare",
- "idx": 0,
- "is_complete": 0,
- "modified": "2021-01-30 19:22:20.273766",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Healthcare",
- "owner": "Administrator",
- "steps": [
- {
- "step": "Create Patient"
- },
- {
- "step": "Create Practitioner Schedule"
- },
- {
- "step": "Introduction to Healthcare Practitioner"
- },
- {
- "step": "Create Healthcare Practitioner"
- },
- {
- "step": "Explore Healthcare Settings"
- },
- {
- "step": "Explore Clinical Procedure Templates"
- }
- ],
- "subtitle": "Patients, Practitioner Schedules, Settings, and more.",
- "success_message": "The Healthcare Module is all set up!",
- "title": "Let's Set Up the Healthcare Module."
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json b/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json
deleted file mode 100644
index 3e4d4e27dff..00000000000
--- a/erpnext/healthcare/number_card/appointments_to_bill/appointments_to_bill.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "creation": "2020-07-14 18:17:54.792773",
- "docstatus": 0,
- "doctype": "Number Card",
- "document_type": "Patient Appointment",
- "dynamic_filters_json": "[[\"Patient Appointment\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
- "filters_json": "[[\"Patient Appointment\",\"invoiced\",\"=\",0,false]]",
- "function": "Count",
- "idx": 0,
- "is_public": 1,
- "is_standard": 1,
- "label": "Appointments To Bill",
- "modified": "2020-07-22 13:27:58.038577",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Appointments to Bill",
- "owner": "Administrator",
- "show_percentage_stats": 1,
- "stats_time_interval": "Daily",
- "type": "Document Type"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/number_card/open_appointments/open_appointments.json b/erpnext/healthcare/number_card/open_appointments/open_appointments.json
deleted file mode 100644
index 8d121cc58a6..00000000000
--- a/erpnext/healthcare/number_card/open_appointments/open_appointments.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "creation": "2020-07-14 18:17:54.771092",
- "docstatus": 0,
- "doctype": "Number Card",
- "document_type": "Patient Appointment",
- "dynamic_filters_json": "[[\"Patient Appointment\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
- "filters_json": "[[\"Patient Appointment\",\"status\",\"=\",\"Open\",false]]",
- "function": "Count",
- "idx": 0,
- "is_public": 1,
- "is_standard": 1,
- "label": "Open Appointments",
- "modified": "2020-07-22 13:27:09.542122",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Open Appointments",
- "owner": "Administrator",
- "show_percentage_stats": 1,
- "stats_time_interval": "Daily",
- "type": "Document Type"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/number_card/total_patients/total_patients.json b/erpnext/healthcare/number_card/total_patients/total_patients.json
deleted file mode 100644
index 75441a6842d..00000000000
--- a/erpnext/healthcare/number_card/total_patients/total_patients.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "creation": "2020-07-14 18:17:54.727946",
- "docstatus": 0,
- "doctype": "Number Card",
- "document_type": "Patient",
- "filters_json": "[[\"Patient\",\"status\",\"=\",\"Active\",false]]",
- "function": "Count",
- "idx": 0,
- "is_public": 1,
- "is_standard": 1,
- "label": "Total Patients",
- "modified": "2020-07-22 13:26:02.643534",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Total Patients",
- "owner": "Administrator",
- "show_percentage_stats": 1,
- "stats_time_interval": "Daily",
- "type": "Document Type"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json b/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json
deleted file mode 100644
index 69a967df938..00000000000
--- a/erpnext/healthcare/number_card/total_patients_admitted/total_patients_admitted.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "creation": "2020-07-14 18:17:54.749754",
- "docstatus": 0,
- "doctype": "Number Card",
- "document_type": "Patient",
- "filters_json": "[[\"Patient\",\"inpatient_status\",\"=\",\"Admitted\",false]]",
- "function": "Count",
- "idx": 0,
- "is_public": 1,
- "is_standard": 1,
- "label": "Total Patients Admitted",
- "modified": "2020-07-22 13:26:20.027788",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Total Patients Admitted",
- "owner": "Administrator",
- "show_percentage_stats": 1,
- "stats_time_interval": "Daily",
- "type": "Document Type"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
deleted file mode 100644
index 3f25a9d6760..00000000000
--- a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "action": "Create Entry",
- "creation": "2020-05-19 10:39:55.728058",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "idx": 0,
- "is_complete": 0,
- "is_single": 0,
- "is_skipped": 0,
- "modified": "2021-01-30 12:02:22.849260",
- "modified_by": "Administrator",
- "name": "Create Healthcare Practitioner",
- "owner": "Administrator",
- "reference_document": "Healthcare Practitioner",
- "show_form_tour": 0,
- "show_full_form": 1,
- "title": "Create Healthcare Practitioner",
- "validate_action": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
deleted file mode 100644
index b46bb15b48a..00000000000
--- a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "action": "Create Entry",
- "creation": "2020-05-19 10:32:27.648902",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "idx": 0,
- "is_complete": 0,
- "is_single": 0,
- "is_skipped": 0,
- "modified": "2021-01-30 00:09:28.786428",
- "modified_by": "ruchamahabal2@gmail.com",
- "name": "Create Patient",
- "owner": "Administrator",
- "reference_document": "Patient",
- "show_form_tour": 0,
- "show_full_form": 1,
- "title": "Create Patient",
- "validate_action": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
deleted file mode 100644
index 7ce122d5c0b..00000000000
--- a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "action": "Create Entry",
- "creation": "2020-05-19 10:41:19.065753",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "idx": 0,
- "is_complete": 0,
- "is_single": 0,
- "is_skipped": 0,
- "modified": "2021-01-30 00:09:28.794602",
- "modified_by": "ruchamahabal2@gmail.com",
- "name": "Create Practitioner Schedule",
- "owner": "Administrator",
- "reference_document": "Practitioner Schedule",
- "show_form_tour": 0,
- "show_full_form": 1,
- "title": "Create Practitioner Schedule",
- "validate_action": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
deleted file mode 100644
index dfe9f71a76f..00000000000
--- a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "action": "Show Form Tour",
- "creation": "2020-05-19 11:40:51.963741",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "idx": 0,
- "is_complete": 0,
- "is_single": 0,
- "is_skipped": 0,
- "modified": "2021-01-30 19:22:08.257160",
- "modified_by": "Administrator",
- "name": "Explore Clinical Procedure Templates",
- "owner": "Administrator",
- "reference_document": "Clinical Procedure Template",
- "show_form_tour": 0,
- "show_full_form": 0,
- "title": "Explore Clinical Procedure Templates",
- "validate_action": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
deleted file mode 100644
index 2d952f30938..00000000000
--- a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "action": "Show Form Tour",
- "creation": "2020-05-19 11:14:33.044989",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "idx": 0,
- "is_complete": 0,
- "is_single": 1,
- "is_skipped": 0,
- "modified": "2021-01-30 19:22:07.275735",
- "modified_by": "Administrator",
- "name": "Explore Healthcare Settings",
- "owner": "Administrator",
- "reference_document": "Healthcare Settings",
- "show_form_tour": 0,
- "show_full_form": 0,
- "title": "Explore Healthcare Settings",
- "validate_action": 1
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
deleted file mode 100644
index baa8358c060..00000000000
--- a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "action": "Show Form Tour",
- "creation": "2020-05-19 10:43:56.231679",
- "docstatus": 0,
- "doctype": "Onboarding Step",
- "field": "schedule",
- "idx": 0,
- "is_complete": 0,
- "is_single": 0,
- "is_skipped": 0,
- "modified": "2021-01-30 00:09:28.807129",
- "modified_by": "ruchamahabal2@gmail.com",
- "name": "Introduction to Healthcare Practitioner",
- "owner": "Administrator",
- "reference_document": "Healthcare Practitioner",
- "show_form_tour": 0,
- "show_full_form": 0,
- "title": "Introduction to Healthcare Practitioner",
- "validate_action": 0
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/page/__init__.py b/erpnext/healthcare/page/__init__.py
deleted file mode 100644
index baffc488252..00000000000
--- a/erpnext/healthcare/page/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/erpnext/healthcare/page/patient_history/__init__.py b/erpnext/healthcare/page/patient_history/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css
deleted file mode 100644
index 74b5e7eb918..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history.css
+++ /dev/null
@@ -1,151 +0,0 @@
-#page-medical_record .label {
- display: inline-block;
- margin-right: 7px;
-}
-
-#page-medical_record .list-row {
- border: none;
- padding: 0px;
- cursor: pointer;
-}
-
-.patient-image-container {
- margin-top: 17px;
- }
-
-.patient-image {
- display: inline-block;
- width: 100%;
- height: 0;
- padding: 50% 0px;
- background-size: cover;
- background-repeat: no-repeat;
- background-position: center center;
- border-radius: 4px;
-}
-
-.patient-name {
- font-size: 20px;
- margin-top: 25px;
-}
-
-.medical_record-label {
- max-width: 100px;
- margin-bottom: -4px;
-}
-
-.medical_record-row > * {
- z-index: -999;
-}
-
-.date-indicator {
- background:none;
- font-size:12px;
- vertical-align:middle;
- font-weight:bold;
- color:#6c7680;
-}
-.date-indicator::after {
- margin:0 -4px 0 12px;
- content:'';
- display:inline-block;
- height:8px;
- width:8px;
- border-radius:8px;
- background: #d1d8dd;
-}
-
-.date-indicator.blue {
- color: #5e64ff;
-}
-
-.div-bg-color {
- background: #fafbfc;
-}
-
-.bg-color-white {
- background: #FFFFFF;
-}
-
-.d-flex {
- display: flex;
-}
-
-.width-full {
- width: 100%;
-}
-
-.p-3 {
- padding: 16px;
-}
-
-.mt-2 {
- margin-top: 8px;
-}
-
-.mr-3 {
- margin-right: 16px;
-}
-
-.Box {
- background-color: #fff;
- border: 1px solid #d1d5da;
- border-radius: 3px;
-}
-
-.flex-column {
- flex-direction: column;
-}
-
-.avatar {
- display: inline-block;
- overflow: hidden;
- line-height: 1;
- vertical-align: middle;
- border-radius: 3px;
-}
-
-.py-3 {
- padding-top: 16px;
- padding-bottom: 16px;
-}
-
-.border-bottom {
- border-bottom: 1px #e1e4e8 solid;
-}
-
-.date-indicator.blue::after {
- background: #5e64ff;
-}
-
-.medical_record-message {
- border-left: 1px solid #d1d8dd;
- padding: 15px;
- padding-right: 30px;
-}
-
-.medical_record-date {
- padding: 15px;
- padding-right: 0px;
-}
-
-.patient-history-filter {
- margin-left: 35px;
- width: 25%;
-}
-
-#page-medical_record .plot-wrapper {
- padding: 20px 15px;
- border-bottom: 1px solid #d1d8dd;
- text-align: center;
-}
-
-#page-medical_record .plot {
- height: 140px ;
- width: 97% ;
- margin: auto;
-}
-
-#page-medical_record .list-filters {
- display: none ;
-}
diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html
deleted file mode 100644
index d16b38637cd..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js
deleted file mode 100644
index ed2dc52cb11..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history.js
+++ /dev/null
@@ -1,455 +0,0 @@
-frappe.provide('frappe.patient_history');
-frappe.pages['patient_history'].on_page_load = function(wrapper) {
- frappe.ui.make_app_page({
- parent: wrapper,
- title: __('Patient History')
- });
-
- let patient_history = new PatientHistory(wrapper);
- $(wrapper).bind('show', ()=> {
- patient_history.show();
- });
-};
-
-class PatientHistory {
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
- this.sidebar = this.wrapper.find('.layout-side-section');
- this.main_section = this.wrapper.find('.layout-main-section');
- this.start = 0;
- }
-
- show() {
- frappe.breadcrumbs.add('Healthcare');
- this.sidebar.empty();
-
- let me = this;
- let patient = frappe.ui.form.make_control({
- parent: me.sidebar,
- df: {
- fieldtype: 'Link',
- options: 'Patient',
- fieldname: 'patient',
- placeholder: __('Select Patient'),
- only_select: true,
- change: () => {
- me.patient_id = '';
- if (me.patient_id != patient.get_value() && patient.get_value()) {
- me.start = 0;
- me.patient_id = patient.get_value();
- me.make_patient_profile();
- }
- }
- }
- });
- patient.refresh();
-
- if (frappe.route_options && !this.patient_id) {
- patient.set_value(frappe.route_options.patient);
- this.patient_id = frappe.route_options.patient;
- }
-
- this.sidebar.find('[data-fieldname="patient"]').append('
');
- }
-
- make_patient_profile() {
- this.page.set_title(__('Patient History'));
- this.main_section.empty().append(frappe.render_template('patient_history'));
- this.setup_filters();
- this.setup_documents();
- this.show_patient_info();
- this.setup_buttons();
- this.show_patient_vital_charts('bp', 'mmHg', 'Blood Pressure');
- }
-
- setup_filters() {
- $('.doctype-filter').empty();
- let me = this;
-
- frappe.xcall(
- 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes'
- ).then(document_types => {
- let doctype_filter = frappe.ui.form.make_control({
- parent: $('.doctype-filter'),
- df: {
- fieldtype: 'MultiSelectList',
- fieldname: 'document_type',
- placeholder: __('Select Document Type'),
- change: () => {
- me.start = 0;
- me.page.main.find('.patient_documents_list').html('');
- this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
- },
- get_data: () => {
- return document_types.map(document_type => {
- return {
- description: document_type,
- value: document_type
- };
- });
- },
- }
- });
- doctype_filter.refresh();
-
- $('.date-filter').empty();
- let date_range_field = frappe.ui.form.make_control({
- df: {
- fieldtype: 'DateRange',
- fieldname: 'date_range',
- placeholder: __('Date Range'),
- input_class: 'input-xs',
- change: () => {
- let selected_date_range = date_range_field.get_value();
- if (selected_date_range && selected_date_range.length === 2) {
- me.start = 0;
- me.page.main.find('.patient_documents_list').html('');
- this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
- }
- }
- },
- parent: $('.date-filter')
- });
- date_range_field.refresh();
- });
- }
-
- setup_documents(document_types="", selected_date_range="") {
- let filters = {
- name: this.patient_id,
- start: this.start,
- page_length: 20
- };
- if (document_types)
- filters['document_types'] = document_types;
- if (selected_date_range)
- filters['date_range'] = selected_date_range;
-
- let me = this;
- frappe.call({
- 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
- args: filters,
- callback: function(r) {
- let data = r.message;
- if (data.length) {
- me.add_to_records(data);
- } else {
- me.page.main.find('.patient_documents_list').append(`
-
- ${__('No more records..')}
-
`);
- me.page.main.find('.btn-get-records').hide();
- }
- }
- });
- }
-
- add_to_records(data) {
- let details = "";
- let i;
- for (i=0; i
" + data[i].subject;
- }
- data[i] = this.add_date_separator(data[i]);
-
- if (frappe.user_info(data[i].owner).image) {
- data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
- } else {
- data[i].imgsrc = false;
- }
-
- let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
- time_line_heading += data[i].reference_doctype + " - " +
- `
- ${data[i].reference_name}
- `;
-
- details += `
- `;
- }
- }
-
- this.page.main.find('.patient_documents_list').append(details);
- this.start += data.length;
-
- if (data.length === 20) {
- this.page.main.find(".btn-get-records").show();
- } else {
- this.page.main.find(".btn-get-records").hide();
- this.page.main.find(".patient_documents_list").append(`
-
- ${__('No more records..')}
-
`);
- }
- }
-
- add_date_separator(data) {
- let date = frappe.datetime.str_to_obj(data.communication_date);
- let pdate = '';
- let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(),
- frappe.datetime.obj_to_str(date));
-
- if (diff < 1) {
- pdate = __('Today');
- } else if (diff < 2) {
- pdate = __('Yesterday');
- } else {
- pdate = __('on {0}', [frappe.datetime.global_date_format(date)]);
- }
- data.date_sep = pdate;
- return data;
- }
-
- show_patient_info() {
- this.get_patient_info().then(() => {
- $('.patient-info').empty().append(frappe.render_template('patient_history_sidebar', {
- patient_image: this.patient.image,
- patient_name: this.patient.patient_name,
- patient_gender: this.patient.sex,
- patient_mobile: this.patient.mobile
- }));
- this.show_patient_details();
- });
- }
-
- show_patient_details() {
- let me = this;
- frappe.call({
- 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
- args: {
- patient: me.patient_id
- },
- callback: function(r) {
- let data = r.message;
- let details = ``;
-
- if (data.occupation) details += `
${__('Occupation')} : ${data.occupation}`;
- if (data.blood_group) details += `
${__('Blood Group')} : ${data.blood_group}`;
- if (data.allergies) details += `
${__('Allerigies')} : ${data.allergies.replace("\n", ", ")}`;
- if (data.medication) details += `
${__('Medication')} : ${data.medication.replace("\n", ", ")}`;
- if (data.alcohol_current_use) details += `
${__('Alcohol use')} : ${data.alcohol_current_use}`;
- if (data.alcohol_past_use) details += `
${__('Alcohol past use')} : ${data.alcohol_past_use}`;
- if (data.tobacco_current_use) details += `
${__('Tobacco use')} : ${data.tobacco_current_use}`;
- if (data.tobacco_past_use) details += `
${__('Tobacco past use')} : ${data.tobacco_past_use}`;
- if (data.medical_history) details += `
${__('Medical history')} : ${data.medical_history.replace("\n", ", ")}`;
- if (data.surgical_history) details += `
${__('Surgical history')} : ${data.surgical_history.replace("\n", ", ")}`;
- if (data.surrounding_factors) details += `
${__('Occupational hazards')} : ${data.surrounding_factors.replace("\n", ", ")}`;
- if (data.other_risk_factors) details += `
${__('Other risk factors')} : ${data.other_risk_factors.replace("\n", ", ")}`;
- if (data.patient_details) details += `
${__('More info')} : ${data.patient_details.replace("\n", ", ")}`;
-
- if (details) {
- details = `
` + details + `
`;
- }
-
- me.sidebar.find('.patient-details').html(details);
- }
- });
- }
-
- get_patient_info() {
- return frappe.xcall('frappe.client.get', {
- doctype: 'Patient',
- name: this.patient_id,
- }).then((patient) => {
- if (patient) {
- this.patient = patient;
- }
- });
- }
-
- setup_buttons() {
- let me = this;
- this.page.main.on("click", ".btn-show-chart", function() {
- let btn_id = $(this).attr("data-show-chart-id"), scale_unit = $(this).attr("data-pts");
- let title = $(this).attr("data-title");
- me.show_patient_vital_charts(btn_id, scale_unit, title);
- });
-
- this.page.main.on('click', '.btn-more', function() {
- let doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname');
- if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') {
- me.page.main.find('.'+docname).hide();
- me.page.main.find('.'+docname).parent().find('.document-html').show();
- } else {
- if (doctype && docname) {
- let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date', 'naming_series'];
- frappe.call({
- method: 'erpnext.healthcare.utils.render_doc_as_html',
- args: {
- doctype: doctype,
- docname: docname,
- exclude_fields: exclude
- },
- freeze: true,
- callback: function(r) {
- if (r.message) {
- me.page.main.find('.' + docname).hide();
-
- me.page.main.find('.' + docname).parent().find('.document-html').html(
- `${r.message.html}
-
-
- `);
-
- me.page.main.find('.' + docname).parent().find('.document-html').attr('hidden', false);
- me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1');
- }
- }
- });
- }
- }
- });
-
- this.page.main.on('click', '.btn-less', function() {
- let docname = $(this).attr('data-docname');
- me.page.main.find('.' + docname).parent().find('.document-id').show();
- me.page.main.find('.' + docname).parent().find('.document-html').hide();
- });
-
- me.page.main.on('click', '.btn-get-records', function() {
- this.setup_documents();
- });
- }
-
- show_patient_vital_charts(btn_id, scale_unit, title) {
- let me = this;
-
- frappe.call({
- method: 'erpnext.healthcare.utils.get_patient_vitals',
- args: {
- patient: me.patient_id
- },
- callback: function(r) {
- if (r.message) {
- let show_chart_btns_html = `
-
`;
-
- me.page.main.find('.show_chart_btns').html(show_chart_btns_html);
- let data = r.message;
- let labels = [], datasets = [];
- let bp_systolic = [], bp_diastolic = [], temperature = [];
- let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = [];
-
- for (let i=0; i
(d + '').toUpperCase(),
- formatTooltipY: d => d + ' ' + scale_unit,
- }
- });
- me.page.main.find('.header-separator').show();
- } else {
- me.page.main.find('.patient_vital_charts').html('');
- me.page.main.find('.show_chart_btns').html('');
- me.page.main.find('.header-separator').hide();
- }
- }
- });
- }
-}
diff --git a/erpnext/healthcare/page/patient_history/patient_history.json b/erpnext/healthcare/page/patient_history/patient_history.json
deleted file mode 100644
index b3892a41c60..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "content": null,
- "creation": "2018-08-08 17:09:13.816199",
- "docstatus": 0,
- "doctype": "Page",
- "icon": "",
- "idx": 0,
- "modified": "2018-08-08 17:09:55.969424",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "patient_history",
- "owner": "Administrator",
- "page_name": "patient_history",
- "restrict_to_domain": "Healthcare",
- "roles": [
- {
- "role": "Healthcare Administrator"
- },
- {
- "role": "Physician"
- }
- ],
- "script": null,
- "standard": "Yes",
- "style": null,
- "system_page": 0,
- "title": "Patient History"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/page/patient_history/patient_history.py b/erpnext/healthcare/page/patient_history/patient_history.py
deleted file mode 100644
index 77d8846f373..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, ESS LLP and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import json
-
-import frappe
-from frappe.utils import cint
-
-
-@frappe.whitelist()
-def get_feed(name, document_types=None, date_range=None, start=0, page_length=20):
- """get feed"""
- filters = get_filters(name, document_types, date_range)
-
- result = frappe.db.get_all('Patient Medical Record',
- fields=['name', 'owner', 'communication_date',
- 'reference_doctype', 'reference_name', 'subject'],
- filters=filters,
- order_by='communication_date DESC',
- limit=cint(page_length),
- start=cint(start)
- )
-
- return result
-
-
-def get_filters(name, document_types=None, date_range=None):
- filters = {'patient': name}
- if document_types:
- document_types = json.loads(document_types)
- if len(document_types):
- filters['reference_doctype'] = ['IN', document_types]
-
- if date_range:
- try:
- date_range = json.loads(date_range)
- if date_range:
- filters['communication_date'] = ['between', [date_range[0], date_range[1]]]
- except json.decoder.JSONDecodeError:
- pass
-
- return filters
-
-
-@frappe.whitelist()
-def get_feed_for_dt(doctype, docname):
- """get feed"""
- result = frappe.db.get_all('Patient Medical Record',
- fields=['name', 'owner', 'communication_date',
- 'reference_doctype', 'reference_name', 'subject'],
- filters={
- 'reference_doctype': doctype,
- 'reference_name': docname
- },
- order_by='communication_date DESC'
- )
-
- return result
-
-
-@frappe.whitelist()
-def get_patient_history_doctypes():
- document_types = []
- settings = frappe.get_single("Patient History Settings")
-
- for entry in settings.standard_doctypes:
- document_types.append(entry.document_type)
-
- for entry in settings.custom_doctypes:
- document_types.append(entry.document_type)
-
- return document_types
diff --git a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html
deleted file mode 100644
index fc7eab05401..00000000000
--- a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
diff --git a/erpnext/healthcare/page/patient_progress/__init__.py b/erpnext/healthcare/page/patient_progress/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.css b/erpnext/healthcare/page/patient_progress/patient_progress.css
deleted file mode 100644
index 737b2e0ea28..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress.css
+++ /dev/null
@@ -1,171 +0,0 @@
-/* sidebar */
-
-.layout-side-section .frappe-control[data-fieldname='patient'] {
- max-width: 300px;
-}
-
-.patient-image-container {
- margin-top: 17px;
-}
-
-.patient-image {
- display: inline-block;
- width: 100%;
- height: 0;
- padding: 50% 0px;
- background-size: cover;
- background-repeat: no-repeat;
- background-position: center center;
- border-radius: 4px;
-}
-
-.patient-details {
- margin: -5px 5px;
-}
-
-.important-links {
- margin: 30px 5px;
-}
-
-.patient-name {
- font-size: 20px;
- margin-top: 25px;
-}
-
-/* heatmap */
-
-.heatmap-container {
- height: 170px;
-}
-
-.patient-heatmap {
- width: 80%;
- display: inline-block;
-}
-
-.patient-heatmap .chart-container {
- margin-left: 30px;
-}
-
-.patient-heatmap .frappe-chart {
- margin-top: 5px;
-}
-
-.patient-heatmap .frappe-chart .chart-legend {
- display: none;
-}
-
-.heatmap-container .chart-filter {
- z-index: 1;
- position: relative;
- top: 5px;
- margin-right: 10px;
-}
-
-/* percentage chart */
-
-.percentage-chart-container {
- height: 130px;
-}
-
-.percentage-chart-container .chart-filter {
- position: relative;
- top: 5px;
- margin-right: 10px;
-}
-
-.therapy-session-percentage-chart .frappe-chart {
- position: absolute;
- top: 5px;
-}
-
-/* line charts */
-
-.date-field .clearfix {
- display: none;
-}
-
-.date-field .help-box {
- display: none;
-}
-
-.date-field .frappe-control {
- margin-bottom: 0px !important;
-}
-
-.date-field .form-group {
- margin-bottom: 0px !important;
-}
-
-/* common */
-
-text.title {
- text-transform: uppercase;
- font-size: 11px;
- margin-left: 20px;
- margin-top: 20px;
- display: block;
-}
-
-.chart-filter-search {
- margin-left: 35px;
- width: 25%;
-}
-
-.chart-column-container {
- margin: 5px 0;
-}
-
-.progress-graphs .progress-container {
- margin-bottom: var(--margin-xl);
-}
-
-.line-chart-container .frappe-chart {
- margin-top: -20px;
-}
-
-.line-chart-container {
- margin-bottom: 20px;
-}
-
-.chart-control {
- align-self: center;
- display: flex;
- flex-direction: row-reverse;
- margin-top: -25px;
-}
-
-.chart-control > * {
- margin-right: 10px;
-}
-
-/* mobile */
-
-@media (max-width: 991px) {
- .patient-progress-sidebar {
- display: flex;
- }
-
- .percentage-chart-container {
- border-top: 1px solid #d1d8dd;
- }
-
- .percentage-chart-container .chart-filter {
- z-index: 1;
- position: relative;
- top: 12px;
- margin-right: 10px;
- }
-
- .patient-progress-sidebar .important-links {
- margin: 0;
- }
-
- .patient-progress-sidebar .patient-details {
- width: 50%;
- }
-
- .chart-filter-search {
- width: 40%;
- }
-}
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html
deleted file mode 100644
index ee60065618f..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Therapy Type and Assessment Correlation
-
-
-
-
-
-
-
-
-
Assessment Parameter Wise Progress
-
-
-
-
-
-
-
-
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.js b/erpnext/healthcare/page/patient_progress/patient_progress.js
deleted file mode 100644
index 3f06f1feba6..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress.js
+++ /dev/null
@@ -1,536 +0,0 @@
-frappe.pages['patient-progress'].on_page_load = function(wrapper) {
-
- frappe.ui.make_app_page({
- parent: wrapper,
- title: __('Patient Progress')
- });
-
- let patient_progress = new PatientProgress(wrapper);
- $(wrapper).bind('show', ()=> {
- patient_progress.show();
- });
-};
-
-class PatientProgress {
-
- constructor(wrapper) {
- this.wrapper = $(wrapper);
- this.page = wrapper.page;
- this.sidebar = this.wrapper.find('.layout-side-section');
- this.main_section = this.wrapper.find('.layout-main-section');
- }
-
- show() {
- frappe.breadcrumbs.add('Healthcare');
- this.sidebar.empty();
-
- let me = this;
- let patient = frappe.ui.form.make_control({
- parent: me.sidebar,
- df: {
- fieldtype: 'Link',
- options: 'Patient',
- fieldname: 'patient',
- placeholder: __('Select Patient'),
- only_select: true,
- change: () => {
- me.patient_id = '';
- if (me.patient_id != patient.get_value() && patient.get_value()) {
- me.start = 0;
- me.patient_id = patient.get_value();
- me.make_patient_profile();
- }
- }
- }
- });
- patient.refresh();
-
- if (frappe.route_options && !this.patient) {
- patient.set_value(frappe.route_options.patient);
- this.patient_id = frappe.route_options.patient;
- }
-
- this.sidebar.find('[data-fieldname="patient"]').append('
');
- }
-
- make_patient_profile() {
- this.page.set_title(__('Patient Progress'));
- this.main_section.empty().append(frappe.render_template('patient_progress'));
- this.render_patient_details();
- this.render_heatmap();
- this.render_percentage_chart('therapy_type', 'Therapy Type Distribution');
- this.create_percentage_chart_filters();
- this.show_therapy_progress();
- this.show_assessment_results();
- this.show_therapy_assessment_correlation();
- this.show_assessment_parameter_progress();
- }
-
- get_patient_info() {
- return frappe.xcall('frappe.client.get', {
- doctype: 'Patient',
- name: this.patient_id
- }).then((patient) => {
- if (patient) {
- this.patient = patient;
- }
- });
- }
-
- get_therapy_sessions_count() {
- return frappe.xcall(
- 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_count', {
- patient: this.patient_id,
- }
- ).then(data => {
- if (data) {
- this.total_therapy_sessions = data.total_therapy_sessions;
- this.therapy_sessions_this_month = data.therapy_sessions_this_month;
- }
- });
- }
-
- render_patient_details() {
- this.get_patient_info().then(() => {
- this.get_therapy_sessions_count().then(() => {
- $('.patient-info').empty().append(frappe.render_template('patient_progress_sidebar', {
- patient_image: this.patient.image,
- patient_name: this.patient.patient_name,
- patient_gender: this.patient.sex,
- patient_mobile: this.patient.mobile,
- total_therapy_sessions: this.total_therapy_sessions,
- therapy_sessions_this_month: this.therapy_sessions_this_month
- }));
-
- this.setup_patient_profile_links();
- });
- });
- }
-
- setup_patient_profile_links() {
- this.wrapper.find('.patient-profile-link').on('click', () => {
- frappe.set_route('Form', 'Patient', this.patient_id);
- });
-
- this.wrapper.find('.therapy-plan-link').on('click', () => {
- frappe.route_options = {
- 'patient': this.patient_id,
- 'docstatus': 1
- };
- frappe.set_route('List', 'Therapy Plan');
- });
-
- this.wrapper.find('.patient-history').on('click', () => {
- frappe.route_options = {
- 'patient': this.patient_id
- };
- frappe.set_route('patient_history');
- });
- }
-
- render_heatmap() {
- this.heatmap = new frappe.Chart('.patient-heatmap', {
- type: 'heatmap',
- countLabel: 'Interactions',
- data: {},
- discreteDomains: 1,
- radius: 3,
- height: 150
- });
-
- this.update_heatmap_data();
- this.create_heatmap_chart_filters();
- }
-
- update_heatmap_data(date_from) {
- frappe.xcall('erpnext.healthcare.page.patient_progress.patient_progress.get_patient_heatmap_data', {
- patient: this.patient_id,
- date: date_from || frappe.datetime.year_start(),
- }).then((data) => {
- this.heatmap.update( {dataPoints: data} );
- });
- }
-
- create_heatmap_chart_filters() {
- this.get_patient_info().then(() => {
- let filters = [
- {
- label: frappe.dashboard_utils.get_year(frappe.datetime.now_date()),
- options: frappe.dashboard_utils.get_years_since_creation(this.patient.creation),
- action: (selected_item) => {
- this.update_heatmap_data(frappe.datetime.obj_to_str(selected_item));
- }
- },
- ];
- frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.heatmap-container');
- });
- }
-
- render_percentage_chart(field, title) {
- // REDESIGN-TODO: chart seems to be broken. Enable this once fixed.
- this.wrapper.find('.percentage-chart-container').hide();
- // frappe.xcall(
- // 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_distribution_data', {
- // patient: this.patient_id,
- // field: field
- // }
- // ).then(chart => {
- // if (chart.labels.length) {
- // this.percentage_chart = new frappe.Chart('.therapy-session-percentage-chart', {
- // title: title,
- // type: 'percentage',
- // data: {
- // labels: chart.labels,
- // datasets: chart.datasets
- // },
- // truncateLegends: 1,
- // barOptions: {
- // height: 11,
- // depth: 1
- // },
- // height: 160,
- // maxSlices: 8,
- // colors: ['#5e64ff', '#743ee2', '#ff5858', '#ffa00a', '#feef72', '#28a745', '#98d85b', '#a9a7ac'],
- // });
- // } else {
- // this.wrapper.find('.percentage-chart-container').hide();
- // }
- // });
- }
-
- create_percentage_chart_filters() {
- let filters = [
- {
- label: 'Therapy Type',
- options: ['Therapy Type', 'Exercise Type'],
- fieldnames: ['therapy_type', 'exercise_type'],
- action: (selected_item, fieldname) => {
- let title = selected_item + ' Distribution';
- this.render_percentage_chart(fieldname, title);
- }
- },
- ];
- frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', '.percentage-chart-container');
- }
-
- create_time_span_filters(action_method, parent) {
- let chart_control = $(parent).find('.chart-control');
- let filters = [
- {
- label: 'Last Month',
- options: ['Select Date Range', 'Last Week', 'Last Month', 'Last Quarter', 'Last Year'],
- action: (selected_item) => {
- if (selected_item === 'Select Date Range') {
- this.render_date_range_fields(action_method, chart_control);
- } else {
- // hide date range field if visible
- let date_field = $(parent).find('.date-field');
- if (date_field.is(':visible')) {
- date_field.hide();
- }
- this[action_method](selected_item);
- }
- }
- }
- ];
- frappe.dashboard_utils.render_chart_filters(filters, 'chart-filter', chart_control, 1);
- }
-
- render_date_range_fields(action_method, parent) {
- let date_field = $(parent).find('.date-field');
-
- if (!date_field.length) {
- let date_field_wrapper = $(
- `
`
- ).appendTo(parent);
-
- let date_range_field = frappe.ui.form.make_control({
- df: {
- fieldtype: 'DateRange',
- fieldname: 'from_date',
- placeholder: 'Date Range',
- input_class: 'input-xs',
- reqd: 1,
- change: () => {
- let selected_date_range = date_range_field.get_value();
- if (selected_date_range && selected_date_range.length === 2) {
- this[action_method](selected_date_range);
- }
- }
- },
- parent: date_field_wrapper,
- render_input: 1
- });
- } else if (!date_field.is(':visible')) {
- date_field.show();
- }
- }
-
- show_therapy_progress() {
- let me = this;
- let therapy_type = frappe.ui.form.make_control({
- parent: $('.therapy-type-search'),
- df: {
- fieldtype: 'Link',
- options: 'Therapy Type',
- fieldname: 'therapy_type',
- placeholder: __('Select Therapy Type'),
- only_select: true,
- change: () => {
- if (me.therapy_type != therapy_type.get_value() && therapy_type.get_value()) {
- me.therapy_type = therapy_type.get_value();
- me.render_therapy_progress_chart();
- }
- }
- }
- });
- therapy_type.refresh();
- this.create_time_span_filters('render_therapy_progress_chart', '.therapy-progress');
- }
-
- render_therapy_progress_chart(time_span='Last Month') {
- if (!this.therapy_type) return;
-
- frappe.xcall(
- 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_progress_data', {
- patient: this.patient_id,
- therapy_type: this.therapy_type,
- time_span: time_span
- }
- ).then(chart => {
- let data = {
- labels: chart.labels,
- datasets: chart.datasets
- }
- let parent = '.therapy-progress-line-chart';
- if (!chart.labels.length) {
- this.show_null_state(parent);
- } else {
- if (!this.therapy_line_chart) {
- this.therapy_line_chart = new frappe.Chart(parent, {
- type: 'axis-mixed',
- height: 250,
- data: data,
- lineOptions: {
- regionFill: 1
- },
- axisOptions: {
- xIsSeries: 1
- }
- });
- } else {
- $(parent).find('.chart-container').show();
- $(parent).find('.chart-empty-state').hide();
- this.therapy_line_chart.update(data);
- }
- }
- });
- }
-
- show_assessment_results() {
- let me = this;
- let assessment_template = frappe.ui.form.make_control({
- parent: $('.assessment-template-search'),
- df: {
- fieldtype: 'Link',
- options: 'Patient Assessment Template',
- fieldname: 'assessment_template',
- placeholder: __('Select Assessment Template'),
- only_select: true,
- change: () => {
- if (me.assessment_template != assessment_template.get_value() && assessment_template.get_value()) {
- me.assessment_template = assessment_template.get_value();
- me.render_assessment_result_chart();
- }
- }
- }
- });
- assessment_template.refresh();
- this.create_time_span_filters('render_assessment_result_chart', '.assessment-results');
- }
-
- render_assessment_result_chart(time_span='Last Month') {
- if (!this.assessment_template) return;
-
- frappe.xcall(
- 'erpnext.healthcare.page.patient_progress.patient_progress.get_patient_assessment_data', {
- patient: this.patient_id,
- assessment_template: this.assessment_template,
- time_span: time_span
- }
- ).then(chart => {
- let data = {
- labels: chart.labels,
- datasets: chart.datasets,
- yMarkers: [
- { label: 'Max Score', value: chart.max_score }
- ],
- }
- let parent = '.assessment-results-line-chart';
- if (!chart.labels.length) {
- this.show_null_state(parent);
- } else {
- if (!this.assessment_line_chart) {
- this.assessment_line_chart = new frappe.Chart(parent, {
- type: 'axis-mixed',
- height: 250,
- data: data,
- lineOptions: {
- regionFill: 1
- },
- axisOptions: {
- xIsSeries: 1
- },
- tooltipOptions: {
- formatTooltipY: d => __('{0} out of {1}', [d, chart.max_score])
- }
- });
- } else {
- $(parent).find('.chart-container').show();
- $(parent).find('.chart-empty-state').hide();
- this.assessment_line_chart.update(data);
- }
- }
- });
- }
-
- show_therapy_assessment_correlation() {
- let me = this;
- let assessment = frappe.ui.form.make_control({
- parent: $('.assessment-correlation-template-search'),
- df: {
- fieldtype: 'Link',
- options: 'Patient Assessment Template',
- fieldname: 'assessment',
- placeholder: __('Select Assessment Template'),
- only_select: true,
- change: () => {
- if (me.assessment != assessment.get_value() && assessment.get_value()) {
- me.assessment = assessment.get_value();
- me.render_therapy_assessment_correlation_chart();
- }
- }
- }
- });
- assessment.refresh();
- this.create_time_span_filters('render_therapy_assessment_correlation_chart', '.therapy-assessment-correlation');
- }
-
- render_therapy_assessment_correlation_chart(time_span='Last Month') {
- if (!this.assessment) return;
-
- frappe.xcall(
- 'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_assessment_correlation_data', {
- patient: this.patient_id,
- assessment_template: this.assessment,
- time_span: time_span
- }
- ).then(chart => {
- let data = {
- labels: chart.labels,
- datasets: chart.datasets,
- yMarkers: [
- { label: 'Max Score', value: chart.max_score }
- ],
- }
- let parent = '.therapy-assessment-correlation-chart';
- if (!chart.labels.length) {
- this.show_null_state(parent);
- } else {
- if (!this.correlation_chart) {
- this.correlation_chart = new frappe.Chart(parent, {
- type: 'axis-mixed',
- height: 300,
- data: data,
- axisOptions: {
- xIsSeries: 1
- }
- });
- } else {
- $(parent).find('.chart-container').show();
- $(parent).find('.chart-empty-state').hide();
- this.correlation_chart.update(data);
- }
- }
- });
- }
-
- show_assessment_parameter_progress() {
- let me = this;
- let parameter = frappe.ui.form.make_control({
- parent: $('.assessment-parameter-search'),
- df: {
- fieldtype: 'Link',
- options: 'Patient Assessment Parameter',
- fieldname: 'assessment',
- placeholder: __('Select Assessment Parameter'),
- only_select: true,
- change: () => {
- if (me.parameter != parameter.get_value() && parameter.get_value()) {
- me.parameter = parameter.get_value();
- me.render_assessment_parameter_progress_chart();
- }
- }
- }
- });
- parameter.refresh();
- this.create_time_span_filters('render_assessment_parameter_progress_chart', '.assessment-parameter-progress');
- }
-
- render_assessment_parameter_progress_chart(time_span='Last Month') {
- if (!this.parameter) return;
-
- frappe.xcall(
- 'erpnext.healthcare.page.patient_progress.patient_progress.get_assessment_parameter_data', {
- patient: this.patient_id,
- parameter: this.parameter,
- time_span: time_span
- }
- ).then(chart => {
- let data = {
- labels: chart.labels,
- datasets: chart.datasets
- }
- let parent = '.assessment-parameter-progress-chart';
- if (!chart.labels.length) {
- this.show_null_state(parent);
- } else {
- if (!this.parameter_chart) {
- this.parameter_chart = new frappe.Chart(parent, {
- type: 'line',
- height: 250,
- data: data,
- lineOptions: {
- regionFill: 1
- },
- axisOptions: {
- xIsSeries: 1
- },
- tooltipOptions: {
- formatTooltipY: d => d + '%'
- }
- });
- } else {
- $(parent).find('.chart-container').show();
- $(parent).find('.chart-empty-state').hide();
- this.parameter_chart.update(data);
- }
- }
- });
- }
-
- show_null_state(parent) {
- let null_state = $(parent).find('.chart-empty-state');
- if (null_state.length) {
- $(null_state).show();
- } else {
- null_state = $(
- `${__(
- "No Data..."
- )}
`
- );
- $(parent).append(null_state);
- }
- $(parent).find('.chart-container').hide();
- }
-}
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.json b/erpnext/healthcare/page/patient_progress/patient_progress.json
deleted file mode 100644
index 0175cb9c457..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "content": null,
- "creation": "2020-06-12 15:46:23.111928",
- "docstatus": 0,
- "doctype": "Page",
- "idx": 0,
- "modified": "2020-07-23 21:45:45.540055",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "patient-progress",
- "owner": "Administrator",
- "page_name": "patient-progress",
- "restrict_to_domain": "Healthcare",
- "roles": [
- {
- "role": "Healthcare Administrator"
- },
- {
- "role": "Physician"
- },
- {
- "role": "Patient"
- },
- {
- "role": "System Manager"
- }
- ],
- "script": null,
- "standard": "Yes",
- "style": null,
- "system_page": 0,
- "title": "Patient Progress"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.py b/erpnext/healthcare/page/patient_progress/patient_progress.py
deleted file mode 100644
index c17f10574a9..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress.py
+++ /dev/null
@@ -1,198 +0,0 @@
-import json
-from datetime import datetime
-
-import frappe
-from frappe import _
-from frappe.utils import get_timespan_date_range, getdate
-
-
-@frappe.whitelist()
-def get_therapy_sessions_count(patient):
- total = frappe.db.count('Therapy Session', filters={
- 'docstatus': 1,
- 'patient': patient
- })
-
- month_start = datetime.today().replace(day=1)
- this_month = frappe.db.count('Therapy Session', filters={
- 'creation': ['>', month_start],
- 'docstatus': 1,
- 'patient': patient
- })
-
- return {
- 'total_therapy_sessions': total,
- 'therapy_sessions_this_month': this_month
- }
-
-
-@frappe.whitelist()
-def get_patient_heatmap_data(patient, date):
- return dict(frappe.db.sql("""
- SELECT
- unix_timestamp(communication_date), count(*)
- FROM
- `tabPatient Medical Record`
- WHERE
- communication_date > subdate(%(date)s, interval 1 year) and
- communication_date < subdate(%(date)s, interval -1 year) and
- patient = %(patient)s
- GROUP BY communication_date
- ORDER BY communication_date asc""", {'date': date, 'patient': patient}))
-
-
-@frappe.whitelist()
-def get_therapy_sessions_distribution_data(patient, field):
- if field == 'therapy_type':
- result = frappe.db.get_all('Therapy Session',
- filters = {'patient': patient, 'docstatus': 1},
- group_by = field,
- order_by = field,
- fields = [field, 'count(*)'],
- as_list = True)
-
- elif field == 'exercise_type':
- data = frappe.db.get_all('Therapy Session', filters={
- 'docstatus': 1,
- 'patient': patient
- }, as_list=True)
- therapy_sessions = [entry[0] for entry in data]
-
- result = frappe.db.get_all('Exercise',
- filters = {
- 'parenttype': 'Therapy Session',
- 'parent': ['in', therapy_sessions],
- 'docstatus': 1
- },
- group_by = field,
- order_by = field,
- fields = [field, 'count(*)'],
- as_list = True)
-
- return {
- 'labels': [r[0] for r in result if r[0] != None],
- 'datasets': [{
- 'values': [r[1] for r in result]
- }]
- }
-
-
-@frappe.whitelist()
-def get_therapy_progress_data(patient, therapy_type, time_span):
- date_range = get_date_range(time_span)
- query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'therapy_type': therapy_type, 'patient': patient}
- result = frappe.db.sql("""
- SELECT
- start_date, total_counts_targeted, total_counts_completed
- FROM
- `tabTherapy Session`
- WHERE
- start_date BETWEEN %(from_date)s AND %(to_date)s and
- docstatus = 1 and
- therapy_type = %(therapy_type)s and
- patient = %(patient)s
- ORDER BY start_date""", query_values, as_list=1)
-
- return {
- 'labels': [r[0] for r in result if r[0] != None],
- 'datasets': [
- { 'name': _('Targetted'), 'values': [r[1] for r in result if r[0] != None] },
- { 'name': _('Completed'), 'values': [r[2] for r in result if r[0] != None] }
- ]
- }
-
-@frappe.whitelist()
-def get_patient_assessment_data(patient, assessment_template, time_span):
- date_range = get_date_range(time_span)
- query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment_template': assessment_template, 'patient': patient}
- result = frappe.db.sql("""
- SELECT
- assessment_datetime, total_score, total_score_obtained
- FROM
- `tabPatient Assessment`
- WHERE
- DATE(assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and
- docstatus = 1 and
- assessment_template = %(assessment_template)s and
- patient = %(patient)s
- ORDER BY assessment_datetime""", query_values, as_list=1)
-
- return {
- 'labels': [getdate(r[0]) for r in result if r[0] != None],
- 'datasets': [
- { 'name': _('Score Obtained'), 'values': [r[2] for r in result if r[0] != None] }
- ],
- 'max_score': result[0][1] if result else None
- }
-
-@frappe.whitelist()
-def get_therapy_assessment_correlation_data(patient, assessment_template, time_span):
- date_range = get_date_range(time_span)
- query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'assessment': assessment_template, 'patient': patient}
- result = frappe.db.sql("""
- SELECT
- therapy.therapy_type, count(*), avg(assessment.total_score_obtained), total_score
- FROM
- `tabPatient Assessment` assessment INNER JOIN `tabTherapy Session` therapy
- ON
- assessment.therapy_session = therapy.name
- WHERE
- DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and
- assessment.docstatus = 1 and
- assessment.patient = %(patient)s and
- assessment.assessment_template = %(assessment)s
- GROUP BY therapy.therapy_type
- """, query_values, as_list=1)
-
- return {
- 'labels': [r[0] for r in result if r[0] != None],
- 'datasets': [
- { 'name': _('Sessions'), 'chartType': 'bar', 'values': [r[1] for r in result if r[0] != None] },
- { 'name': _('Average Score'), 'chartType': 'line', 'values': [round(r[2], 2) for r in result if r[0] != None] }
- ],
- 'max_score': result[0][1] if result else None
- }
-
-@frappe.whitelist()
-def get_assessment_parameter_data(patient, parameter, time_span):
- date_range = get_date_range(time_span)
- query_values = {'from_date': date_range[0], 'to_date': date_range[1], 'parameter': parameter, 'patient': patient}
- results = frappe.db.sql("""
- SELECT
- assessment.assessment_datetime,
- sheet.score,
- template.scale_max
- FROM
- `tabPatient Assessment Sheet` sheet
- INNER JOIN `tabPatient Assessment` assessment
- ON sheet.parent = assessment.name
- INNER JOIN `tabPatient Assessment Template` template
- ON template.name = assessment.assessment_template
- WHERE
- DATE(assessment.assessment_datetime) BETWEEN %(from_date)s AND %(to_date)s and
- assessment.docstatus = 1 and
- sheet.parameter = %(parameter)s and
- assessment.patient = %(patient)s
- ORDER BY
- assessment.assessment_datetime asc
- """, query_values, as_list=1)
-
- score_percentages = []
- for r in results:
- if r[2] != 0 and r[0] != None:
- score = round((int(r[1]) / int(r[2])) * 100, 2)
- score_percentages.append(score)
-
- return {
- 'labels': [getdate(r[0]) for r in results if r[0] != None],
- 'datasets': [
- { 'name': _('Score'), 'values': score_percentages }
- ]
- }
-
-def get_date_range(time_span):
- try:
- time_span = json.loads(time_span)
- return time_span
- except json.decoder.JSONDecodeError:
- return get_timespan_date_range(time_span.lower())
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html b/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html
deleted file mode 100644
index 4ee65738ba3..00000000000
--- a/erpnext/healthcare/page/patient_progress/patient_progress_sidebar.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
diff --git a/erpnext/healthcare/print_format/__init__.py b/erpnext/healthcare/print_format/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/print_format/encounter_print/__init__.py b/erpnext/healthcare/print_format/encounter_print/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/print_format/encounter_print/encounter_print.json b/erpnext/healthcare/print_format/encounter_print/encounter_print.json
deleted file mode 100644
index 3c90adb0a1c..00000000000
--- a/erpnext/healthcare/print_format/encounter_print/encounter_print.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "align_labels_right": 0,
- "creation": "2017-04-10 14:05:53.355863",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Patient Encounter",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {% else %}\n
\n
{{doc.name}} \n \n {%- endif %}\n
\n
\n {% if doc.appointment %}\n\t
\n\t\t\t
\n\t\t\tAppointment \n\t\t\t
\n\t\t\t
\n\t\t\t: {{doc.appointment}}\n\t\t\t
\n\t\t
\n\t\t{%- endif -%}\n\n
\n\t\t
\n\t\t\t Patient \n\t\t
\n {% if doc.patient %}\n\t\t
\n\t\t\t : {{doc.patient}}\n\t\t
\n {% else %}\n
\n\t\t\t : Patient Name \n\t\t
\n {%- endif -%}\n\t\t
\n\t
\n\t\t\t
\n\t\t\t\tAge \n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_age}}\n\t\t\t
\n\t\t
\n\n
\n
\n\t\t\t\tGender \n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_sex}}\n\t\t\t
\n
\n\n
\n
\n\n
\n\t
\n\t\t Healthcare Practitioner \n\t
\n {% if doc.practitioner %}\n\t
\n\t\t\t: {{doc.practitioner}}\n\t
\n {%- endif -%}\n\t
\n\n {% if doc.encounter_date %}\n\t
\n\t\t
\n\t\tDate \n\t\t
\n\t\t
\n\t\t: {{doc.encounter_date}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.encounter_time %}\n\t
\n\t\t
\n\t\tTime \n\t\t
\n\t\t
\n\t\t: {{doc.encounter_time}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.medical_department %}\n\t
\n\t\t
\n\t\tDepartment \n\t\t
\n\t\t
\n\t\t: {{doc.visit_department}}\n\t\t
\n
\n {%- endif -%}\n
\n\n
\n\n
\n\n
\n {% if doc.symptoms_in_print%}\n {% if doc.symptoms %}\n Complaints:\n {{doc.symptoms}} \n \t \n {%- endif -%}\n {%- endif -%}\n\n {% if doc.diagnosis_in_print%}\n {% if doc.diagnosis %}\n \t Diagnosis:\n {{doc.diagnosis}} \n \n {%- endif -%}\n {%- endif -%}\n\n\n\n\n {% if doc.drug_prescription %}\n
\n Rx,\n
\n \n \n\n {%- for row in doc.drug_prescription -%}\n \n \n {%- if row.drug_name -%}{{ row.drug_name }} {%- endif -%}\n \n \t\n {%- if row.dosage -%}{{ row.dosage }}{%- endif -%}\n \n \t\n {%- if row.period -%}{{ row.period }}{%- endif -%}\n\t\t \n \n\t\t\t \n {%- if row.comment -%}{{ row.comment }}{%- endif -%}\n
\n\t\t \n \n\t {%- endfor -%}\n \n
\n\n\n {%- endif -%}\n
\n\n\n\n {% if doc.lab_test_prescription %}\n Investigations,\n
\n \n \n\n {%- for row in doc.lab_test_prescription -%}\n \n \n {%- if row.lab_test_name -%}{{ row.lab_test_name }} {%- endif -%}\n \n \n\t\t\t \n {%- if row.lab_test_comment -%}{{ row.lab_test_comment }}{%- endif -%}\n
\n\t\t \n \n\n\t {%- endfor -%}\n \n
\n\n\n {%- endif -%}\n
\n\n {% if doc.encounter_comment %}\n \n {{doc.encounter_comment}}\n {%- endif -%}\n
\n",
- "idx": 0,
- "line_breaks": 0,
- "modified": "2018-09-04 11:52:54.473702",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Encounter Print",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Jinja",
- "show_section_headings": 0,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/print_format/lab_test_print/__init__.py b/erpnext/healthcare/print_format/lab_test_print/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json b/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json
deleted file mode 100644
index f7d16769c66..00000000000
--- a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "align_labels_right": 0,
- "creation": "2017-04-24 15:38:45.332473",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Lab Test",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {%- endif %}\n\n {% if (doc.docstatus != 1) %}\n
WORKSHEET \n\t
\n\t
\n
\n\n
\n
\n Patient \n
\n {% if doc.patient_name %}\n
\n {{ doc.patient_name }}\n
\n {% else %}\n
\n {{ doc.patient }}\n
\n {%- endif -%}\n
\n\n
\n
\n Age \n
\n
\n {{ doc.patient_age or '' }}\n
\n
\n\n
\n
\n Gender \n
\n
\n {{ doc.patient_sex or '' }}\n
\n
\n\n
\n\n
\n\n
\n
\n Practitioner \n
\n {% if doc.practitioner_name %}\n
\n {{ doc.practitioner_name }}\n
\n {% else %}\n\t\t\t{% if doc.referring_practitioner_name %}\n
\n {{ doc.referring_practitioner_name }}\n
\n\t\t {% endif %}\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n Sample Date \n
\n
\n {{ doc.sample_date }}\n
\n
\n {%- endif -%}\n
\n
\n\n\t
\n
Department of {{ doc.department }} \n \n\n\t
\n \n {%- if doc.normal_test_items -%}\n \n Name of Test \n Result \n Normal Range \n \n\n {%- if doc.normal_test_items|length > 1 %}\n {{ doc.lab_test_name }} \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n {%- if doc.normal_test_items|length > 1 %} {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }} \n {%- else -%} {%- endif -%}\n {%- if row.lab_test_event -%} {{ row.lab_test_event }}{%- endif -%}\n \n\n \n {%- if row.lab_test_uom -%} {{ row.lab_test_uom }}{%- endif -%}\n \n\n \n \n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
\n\n\t
\n \n {%- if doc.descriptive_test_items -%}\n \n Name of Test \n Result \n \n {{ doc.lab_test_name }} \n\t\t\t{% set gr_lab_test_name = {'ltname': ''} %}\n {%- for row in doc.descriptive_test_items -%}\n\t\t\t{%- if row.lab_test_name -%}\n\t\t\t{%- if row.lab_test_name != gr_lab_test_name.ltname -%}\n\t\t\t\n\t\t\t\t {{ row.lab_test_name }} \n\t\t\t\t \n\t\t\t \n\t\t\t{% if gr_lab_test_name.update({'ltname': row.lab_test_name}) %} {% endif %}\n\t\t\t{%- endif -%}\n\t\t\t{%- endif -%}\n \n {{ row.lab_test_particulars }} \n \n \n {%- endfor -%}\n {%- endif -%}\n \n
\n
\n {% if doc.worksheet_instructions %}\n
\n Instructions \n {{ doc.worksheet_instructions }}\n {%- endif -%}\n\n {% elif (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"require_test_result_approval\") == '1' and doc.status != \"Approved\") %}\n
Lab Tests have to be Approved for Print .. ! \n {%- else -%}\n
\n
\n\n
\n
\n Patient \n
\n {% if doc.patient_name %}\n
\n {{ doc.patient_name }}\n
\n {% else %}\n
\n {{ doc.patient }}\n
\n {%- endif -%}\n
\n\n
\n
\n Age \n
\n
\n {{ doc.patient_age or '' }}\n
\n
\n\n
\n
\n Gender \n
\n
\n {{ doc.patient_sex or '' }}\n
\n
\n\n
\n\n
\n\n
\n
\n Practitioner \n
\n {% if doc.practitioner_name %}\n
\n {{ doc.practitioner_name }}\n
\n\t\t{% else %}\n\t\t {% if doc.referring_practitioner_name %}\n
\n {{ doc.referring_practitioner_name }}\n
\n\t\t\t{% endif %}\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n Sample Date \n
\n
\n {{ doc.sample_date }}\n
\n
\n {%- endif -%}\n\n {% if doc.result_date %}\n
\n
\n Result Date \n
\n
\n {{ doc.result_date }}\n
\n
\n {%- endif -%}\n\n
\n\n
\n\n
\n
Department of {{ doc.department }} \n \n\n\t
\n\t\t{% if doc.result_legend and (doc.legend_print_position == \"Top\" or doc.legend_print_position == \"Both\")%}\n\t\tResult Legend: \n\t\t{{ doc.result_legend }}\n\t\t{%- endif -%}\n\t
\n\n
\n \n {%- if doc.normal_test_items -%}\n \n Name of Test \n Result \n Normal Range \n \n\n {%- if doc.normal_test_items|length > 1 %}\n {{ doc.lab_test_name }} \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n {%- if doc.normal_test_items|length > 1 %} {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }} \n {%- else -%} {%- endif -%}\n {%- if row.lab_test_event -%} {{ row.lab_test_event }}{%- endif -%}\n \n\n \n\t\t\t\t\t{%- if row.result_value -%}\n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n {{ row.result_value }}\n {%- if row.lab_test_uom -%} {{ row.lab_test_uom }}{%- endif -%}\n\t\t\t\t\t\t{%- if row.italic -%} {% endif %}\n\t\t\t\t\t\t{%- if row.underline -%} {% endif %}\n\t\t\t\t\t\t{%- if row.bold -%} {% endif %}\n\t\t\t\t\t{%- endif -%}\n \n\t\t\t\t\t{%- if row.secondary_uom and row.conversion_factor and row.secondary_uom_result -%}\n\t\t\t\t\t\t \n\t\t\t\t\t\t{%- if row.bold -%}{% endif %}\n\t\t\t\t\t\t{%- if row.underline -%}{% endif %}\n\t\t\t\t\t\t{%- if row.italic -%}{% endif %}\n {{ row.secondary_uom_result }}\n {{ row.secondary_uom }}\n\t\t\t\t\t\t{%- if row.italic -%} {% endif %}\n\t\t\t\t\t\t{%- if row.underline -%} {% endif %}\n\t\t\t\t\t\t{%- if row.bold -%} {% endif %}\n\t\t\t\t\t\t \n\t\t\t\t\t{%- endif -%}\n \n\n \n \n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
\n\n
\n \n {%- if doc.descriptive_test_items -%}\n \n Name of Test \n Result \n \n {{ doc.lab_test_name }} \n\t\t\t{% set gr_lab_test_name = {'ltname': ''} %}\n {%- for row in doc.descriptive_test_items -%}\n\t\t\t{%- if row.lab_test_name -%}\n\t\t\t{%- if row.lab_test_name != gr_lab_test_name.ltname -%}\n\t\t\t\n\t\t\t\t {{ row.lab_test_name }} \n\t\t\t\t \n\t\t\t \n\t\t\t{% if gr_lab_test_name.update({'ltname': row.lab_test_name}) %} {% endif %}\n\t\t\t{%- endif -%}\n\t\t\t{%- endif -%}\n \n {{ row.lab_test_particulars }} \n \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%}\n \n \n {%- endfor -%}\n {%- endif -%}\n\n\t\t\t{%- if doc.organisms -%}\n\t\t\t\n\t\t\t\tOrganism \n\t\t\t\tColony Population \n\t\t\t \n\t\t\t{%- for row in doc.organisms -%}\n\t\t\t\n\t\t\t\t {{ row.organism }} \n\t\t\t\t\n\t\t\t\t\t{{ row.colony_population }}\n\t\t\t\t\t{% if row.colony_uom %}\n\t\t\t\t\t\t{{ row.colony_uom }}\n\t\t\t\t\t{% endif %}\n\t\t\t\t \n\t\t\t \n\t\t\t{%- endfor -%}\n\t\t\t{%- endif -%}\n\n\t\t\t{%- if doc.sensitivity_test_items -%}\n\t\t\t\n\t\t\t\tAntibiotic \n\t\t\t\tSensitivity \n\t\t\t \n\t\t\t{%- for row in doc.sensitivity_test_items -%}\n\t\t\t\n\t\t\t\t {{ row.antibiotic }} \n\t\t\t\t{{ row.antibiotic_sensitivity }} \n\t\t\t \n\t\t\t{%- endfor -%}\n\t\t\t{%- endif -%}\n\n \n
\n
\n {% if doc.custom_result %}\n
\n
{{ doc.custom_result }}
\n {%- endif -%}\n
\n\n
\n {% if doc.lab_test_comment %}\n \n Comments \n {{ doc.lab_test_comment }}\n {%- endif -%}\n
\n\n
\n {%- if (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"employee_name_and_designation_in_print\") == '1') -%}\n {%- if doc.employee_name -%}\n
{{ doc.employee_name }} \n {%- endif -%}\n {%- if doc.employee_designation -%}\n {{ doc.employee_designation }} \n {%- endif -%}\n {%- else -%}\n {%- if frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") -%}\n {{ frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") }} \n {%- endif -%}\n {%- endif -%}\n \n\n
\n {% if doc.result_legend and (doc.legend_print_position == \"Bottom\" or doc.legend_print_position == \"Both\" or doc.legend_print_position == \"\")%}\n
\n Result Legend \n {{ doc.result_legend }}\n {%- endif -%}\n \n {%- endif -%}\n
",
- "idx": 0,
- "line_breaks": 0,
- "modified": "2020-07-08 15:34:28.866798",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Lab Test Print",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Jinja",
- "raw_printing": 0,
- "show_section_headings": 0,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/print_format/sample_id_print/__init__.py b/erpnext/healthcare/print_format/sample_id_print/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json b/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json
deleted file mode 100644
index 4819e6d57ac..00000000000
--- a/erpnext/healthcare/print_format/sample_id_print/sample_id_print.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "align_labels_left": 0,
- "creation": "2017-02-17 17:40:52.967840",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Sample Collection",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "\n{% set column = 0 %}\n\n{% for _ in range(0, doc.num_print) %}\n{% if column == 0 -%}{% endif %}\n\t{{doc.name}} {{doc.patient}} \n{% if doc.patient_age %}{{doc.patient_age}}, {% endif %} {% if doc.patient_sex %}{{doc.patient_sex}}{% endif %} {% if doc.collected_time %}{{doc.collected_time}} {% endif %} {% if doc.collected_by %} {{doc.collected_by}} {% endif %} \n{% if column == 0 %}{% set column = column+1 %}\n{% elif column == 2%} {%- set column = 0 %}\n{% else %}{%- set column = column+1 -%}{%- endif %}\n\t\n{% endfor %}\n
",
- "idx": 0,
- "line_breaks": 0,
- "modified": "2017-03-30 18:09:39.537609",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Sample ID Print",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Jinja",
- "show_section_headings": 0,
- "standard": "Yes"
-}
diff --git a/erpnext/healthcare/report/__init__.py b/erpnext/healthcare/report/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/__init__.py b/erpnext/healthcare/report/inpatient_medication_orders/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js
deleted file mode 100644
index a10f83760fa..00000000000
--- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-/* eslint-disable */
-
-frappe.query_reports["Inpatient Medication Orders"] = {
- "filters": [
- {
- fieldname: "company",
- label: __("Company"),
- fieldtype: "Link",
- options: "Company",
- default: frappe.defaults.get_user_default("Company"),
- reqd: 1
- },
- {
- fieldname: "from_date",
- label: __("From Date"),
- fieldtype: "Date",
- default: frappe.datetime.add_months(frappe.datetime.get_today(), -1),
- reqd: 1
- },
- {
- fieldname: "to_date",
- label: __("To Date"),
- fieldtype: "Date",
- default: frappe.datetime.now_date(),
- reqd: 1
- },
- {
- fieldname: "patient",
- label: __("Patient"),
- fieldtype: "Link",
- options: "Patient"
- },
- {
- fieldname: "service_unit",
- label: __("Healthcare Service Unit"),
- fieldtype: "Link",
- options: "Healthcare Service Unit",
- get_query: () => {
- var company = frappe.query_report.get_filter_value('company');
- return {
- filters: {
- 'company': company,
- 'is_group': 0
- }
- }
- }
- },
- {
- fieldname: "show_completed_orders",
- label: __("Show Completed Orders"),
- fieldtype: "Check",
- default: 1
- }
- ]
-};
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json
deleted file mode 100644
index 9217fa18919..00000000000
--- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "add_total_row": 0,
- "columns": [],
- "creation": "2020-11-23 17:25:58.802949",
- "disable_prepared_report": 0,
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "filters": [],
- "idx": 0,
- "is_standard": "Yes",
- "json": "{}",
- "modified": "2020-11-23 19:40:20.227591",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Inpatient Medication Orders",
- "owner": "Administrator",
- "prepared_report": 0,
- "ref_doctype": "Inpatient Medication Order",
- "report_name": "Inpatient Medication Orders",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "System Manager"
- },
- {
- "role": "Healthcare Administrator"
- },
- {
- "role": "Nursing User"
- },
- {
- "role": "Physician"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
deleted file mode 100644
index 2e809fb66b0..00000000000
--- a/erpnext/healthcare/report/inpatient_medication_orders/inpatient_medication_orders.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-
-from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import (
- get_current_healthcare_service_unit,
-)
-
-
-def execute(filters=None):
- columns = get_columns()
- data = get_data(filters)
- chart = get_chart_data(data)
-
- return columns, data, None, chart
-
-def get_columns():
- return [
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "label": "Patient",
- "options": "Patient",
- "width": 200
- },
- {
- "fieldname": "healthcare_service_unit",
- "fieldtype": "Link",
- "label": "Healthcare Service Unit",
- "options": "Healthcare Service Unit",
- "width": 150
- },
- {
- "fieldname": "drug",
- "fieldtype": "Link",
- "label": "Drug Code",
- "options": "Item",
- "width": 150
- },
- {
- "fieldname": "drug_name",
- "fieldtype": "Data",
- "label": "Drug Name",
- "width": 150
- },
- {
- "fieldname": "dosage",
- "fieldtype": "Link",
- "label": "Dosage",
- "options": "Prescription Dosage",
- "width": 80
- },
- {
- "fieldname": "dosage_form",
- "fieldtype": "Link",
- "label": "Dosage Form",
- "options": "Dosage Form",
- "width": 100
- },
- {
- "fieldname": "date",
- "fieldtype": "Date",
- "label": "Date",
- "width": 100
- },
- {
- "fieldname": "time",
- "fieldtype": "Time",
- "label": "Time",
- "width": 100
- },
- {
- "fieldname": "is_completed",
- "fieldtype": "Check",
- "label": "Is Order Completed",
- "width": 100
- },
- {
- "fieldname": "healthcare_practitioner",
- "fieldtype": "Link",
- "label": "Healthcare Practitioner",
- "options": "Healthcare Practitioner",
- "width": 200
- },
- {
- "fieldname": "inpatient_medication_entry",
- "fieldtype": "Link",
- "label": "Inpatient Medication Entry",
- "options": "Inpatient Medication Entry",
- "width": 200
- },
- {
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "label": "Inpatient Record",
- "options": "Inpatient Record",
- "width": 200
- }
- ]
-
-def get_data(filters):
- conditions, values = get_conditions(filters)
-
- data = frappe.db.sql("""
- SELECT
- parent.patient, parent.inpatient_record, parent.practitioner,
- child.drug, child.drug_name, child.dosage, child.dosage_form,
- child.date, child.time, child.is_completed, child.name
- FROM `tabInpatient Medication Order` parent
- INNER JOIN `tabInpatient Medication Order Entry` child
- ON child.parent = parent.name
- WHERE
- parent.docstatus = 1
- {conditions}
- ORDER BY date, time
- """.format(conditions=conditions), values, as_dict=1)
-
- data = get_inpatient_details(data, filters.get("service_unit"))
-
- return data
-
-def get_conditions(filters):
- conditions = ""
- values = dict()
-
- if filters.get("company"):
- conditions += " AND parent.company = %(company)s"
- values["company"] = filters.get("company")
-
- if filters.get("from_date") and filters.get("to_date"):
- conditions += " AND child.date BETWEEN %(from_date)s and %(to_date)s"
- values["from_date"] = filters.get("from_date")
- values["to_date"] = filters.get("to_date")
-
- if filters.get("patient"):
- conditions += " AND parent.patient = %(patient)s"
- values["patient"] = filters.get("patient")
-
- if not filters.get("show_completed_orders"):
- conditions += " AND child.is_completed = 0"
-
- return conditions, values
-
-
-def get_inpatient_details(data, service_unit):
- service_unit_filtered_data = []
-
- for entry in data:
- entry["healthcare_service_unit"] = get_current_healthcare_service_unit(entry.inpatient_record)
- if entry.is_completed:
- entry["inpatient_medication_entry"] = get_inpatient_medication_entry(entry.name)
-
- if service_unit and entry.healthcare_service_unit and service_unit != entry.healthcare_service_unit:
- service_unit_filtered_data.append(entry)
-
- entry.pop("name", None)
-
- for entry in service_unit_filtered_data:
- data.remove(entry)
-
- return data
-
-def get_inpatient_medication_entry(order_entry):
- return frappe.db.get_value("Inpatient Medication Entry Detail", {"against_imoe": order_entry}, "parent")
-
-def get_chart_data(data):
- if not data:
- return None
-
- labels = ["Pending", "Completed"]
- datasets = []
-
- status_wise_data = {
- "Pending": 0,
- "Completed": 0
- }
-
- for d in data:
- if d.is_completed:
- status_wise_data["Completed"] += 1
- else:
- status_wise_data["Pending"] += 1
-
- datasets.append({
- "name": "Inpatient Medication Order Status",
- "values": [status_wise_data.get("Pending"), status_wise_data.get("Completed")]
- })
-
- chart = {
- "data": {
- "labels": labels,
- "datasets": datasets
- },
- "type": "donut",
- "height": 300
- }
-
- chart["fieldtype"] = "Data"
-
- return chart
diff --git a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
deleted file mode 100644
index 7f7bebf514a..00000000000
--- a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-
-import datetime
-import unittest
-
-import frappe
-from frappe.utils import getdate, now_datetime
-
-from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import (
- create_ipme,
- create_ipmo,
-)
-from erpnext.healthcare.doctype.inpatient_record.inpatient_record import (
- admit_patient,
- discharge_patient,
- schedule_discharge,
-)
-from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import (
- create_inpatient,
- create_patient,
- get_healthcare_service_unit,
- mark_invoiced_inpatient_occupancy,
-)
-from erpnext.healthcare.report.inpatient_medication_orders.inpatient_medication_orders import (
- execute,
-)
-
-
-class TestInpatientMedicationOrders(unittest.TestCase):
- @classmethod
- def setUpClass(self):
- frappe.db.sql("delete from `tabInpatient Medication Order` where company='_Test Company'")
- frappe.db.sql("delete from `tabInpatient Medication Entry` where company='_Test Company'")
- self.patient = create_patient()
- self.ip_record = create_records(self.patient)
-
- def test_inpatient_medication_orders_report(self):
- filters = {
- 'company': '_Test Company',
- 'from_date': getdate(),
- 'to_date': getdate(),
- 'patient': '_Test IPD Patient',
- 'service_unit': '_Test Service Unit Ip Occupancy - _TC'
- }
-
- report = execute(filters)
-
- expected_data = [
- {
- 'patient': '_Test IPD Patient',
- 'inpatient_record': self.ip_record.name,
- 'practitioner': None,
- 'drug': 'Dextromethorphan',
- 'drug_name': 'Dextromethorphan',
- 'dosage': 1.0,
- 'dosage_form': 'Tablet',
- 'date': getdate(),
- 'time': datetime.timedelta(seconds=32400),
- 'is_completed': 0,
- 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC'
- },
- {
- 'patient': '_Test IPD Patient',
- 'inpatient_record': self.ip_record.name,
- 'practitioner': None,
- 'drug': 'Dextromethorphan',
- 'drug_name': 'Dextromethorphan',
- 'dosage': 1.0,
- 'dosage_form': 'Tablet',
- 'date': getdate(),
- 'time': datetime.timedelta(seconds=50400),
- 'is_completed': 0,
- 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC'
- },
- {
- 'patient': '_Test IPD Patient',
- 'inpatient_record': self.ip_record.name,
- 'practitioner': None,
- 'drug': 'Dextromethorphan',
- 'drug_name': 'Dextromethorphan',
- 'dosage': 1.0,
- 'dosage_form': 'Tablet',
- 'date': getdate(),
- 'time': datetime.timedelta(seconds=75600),
- 'is_completed': 0,
- 'healthcare_service_unit': '_Test Service Unit Ip Occupancy - _TC'
- }
- ]
-
- self.assertEqual(expected_data, report[1])
-
- filters = frappe._dict(from_date=getdate(), to_date=getdate(), from_time='', to_time='')
- ipme = create_ipme(filters)
- ipme.submit()
-
- filters = {
- 'company': '_Test Company',
- 'from_date': getdate(),
- 'to_date': getdate(),
- 'patient': '_Test IPD Patient',
- 'service_unit': '_Test Service Unit Ip Occupancy - _TC',
- 'show_completed_orders': 0
- }
-
- report = execute(filters)
- self.assertEqual(len(report[1]), 0)
-
- def tearDown(self):
- if frappe.db.get_value('Patient', self.patient, 'inpatient_record'):
- # cleanup - Discharge
- schedule_discharge(frappe.as_json({'patient': self.patient}))
- self.ip_record.reload()
- mark_invoiced_inpatient_occupancy(self.ip_record)
-
- self.ip_record.reload()
- discharge_patient(self.ip_record)
-
- for entry in frappe.get_all('Inpatient Medication Entry'):
- doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
- doc.cancel()
- doc.delete()
-
- for entry in frappe.get_all('Inpatient Medication Order'):
- doc = frappe.get_doc('Inpatient Medication Order', entry.name)
- doc.cancel()
- doc.delete()
-
-
-def create_records(patient):
- frappe.db.sql("""delete from `tabInpatient Record`""")
-
- # Admit
- ip_record = create_inpatient(patient)
- ip_record.expected_length_of_stay = 0
- ip_record.save()
- ip_record.reload()
- service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy')
- admit_patient(ip_record, service_unit, now_datetime())
-
- ipmo = create_ipmo(patient)
- ipmo.submit()
-
- return ip_record
diff --git a/erpnext/healthcare/report/lab_test_report/__init__.py b/erpnext/healthcare/report/lab_test_report/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.js b/erpnext/healthcare/report/lab_test_report/lab_test_report.js
deleted file mode 100644
index 7754e2e1962..00000000000
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2016, ESS
-// License: See license.txt
-
-frappe.query_reports["Lab Test Report"] = {
- "filters": [
- {
- "fieldname": "from_date",
- "label": __("From Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
- "reqd": 1
- },
- {
- "fieldname": "to_date",
- "label": __("To Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.now_date(),
- "reqd": 1
- },
- {
- "fieldname": "company",
- "label": __("Company"),
- "fieldtype": "Link",
- "default": frappe.defaults.get_default("Company"),
- "options": "Company"
- },
- {
- "fieldname": "template",
- "label": __("Lab Test Template"),
- "fieldtype": "Link",
- "options": "Lab Test Template"
- },
- {
- "fieldname": "patient",
- "label": __("Patient"),
- "fieldtype": "Link",
- "options": "Patient"
- },
- {
- "fieldname": "department",
- "label": __("Medical Department"),
- "fieldtype": "Link",
- "options": "Medical Department"
- },
- {
- "fieldname": "status",
- "label": __("Status"),
- "fieldtype": "Select",
- "options": "\nCompleted\nApproved\nRejected"
- },
- {
- "fieldname": "invoiced",
- "label": __("Invoiced"),
- "fieldtype": "Check"
- }
- ]
-};
diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.json b/erpnext/healthcare/report/lab_test_report/lab_test_report.json
deleted file mode 100644
index aeb42897b8a..00000000000
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "add_total_row": 0,
- "creation": "2013-04-23 18:15:29",
- "disable_prepared_report": 0,
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 1,
- "is_standard": "Yes",
- "modified": "2020-07-30 18:53:20.102873",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Lab Test Report",
- "owner": "Administrator",
- "prepared_report": 0,
- "ref_doctype": "Lab Test",
- "report_name": "Lab Test Report",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Laboratory User"
- },
- {
- "role": "Nursing User"
- },
- {
- "role": "LabTest Approver"
- },
- {
- "role": "Healthcare Administrator"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.py b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
deleted file mode 100644
index e2a53bb1e46..00000000000
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.py
+++ /dev/null
@@ -1,213 +0,0 @@
-# Copyright (c) 2016, ESS
-# License: See license.txt
-
-from __future__ import unicode_literals
-
-import frappe
-from frappe import _, msgprint
-
-
-def execute(filters=None):
- if not filters: filters = {}
-
- data, columns = [], []
-
- columns = get_columns()
- lab_test_list = get_lab_tests(filters)
-
- if not lab_test_list:
- msgprint(_('No records found'))
- return columns, lab_test_list
-
- data = []
- for lab_test in lab_test_list:
- row = frappe._dict({
- 'test': lab_test.name,
- 'template': lab_test.template,
- 'company': lab_test.company,
- 'patient': lab_test.patient,
- 'patient_name': lab_test.patient_name,
- 'practitioner': lab_test.practitioner,
- 'employee': lab_test.employee,
- 'status': lab_test.status,
- 'invoiced': lab_test.invoiced,
- 'result_date': lab_test.result_date,
- 'department': lab_test.department
- })
- data.append(row)
-
- chart = get_chart_data(data)
- report_summary = get_report_summary(data)
- return columns, data, None, chart, report_summary
-
-
-def get_columns():
- return [
- {
- 'fieldname': 'test',
- 'label': _('Lab Test'),
- 'fieldtype': 'Link',
- 'options': 'Lab Test',
- 'width': '120'
- },
- {
- 'fieldname': 'template',
- 'label': _('Lab Test Template'),
- 'fieldtype': 'Link',
- 'options': 'Lab Test Template',
- 'width': '120'
- },
- {
- 'fieldname': 'company',
- 'label': _('Company'),
- 'fieldtype': 'Link',
- 'options': 'Company',
- 'width': '120'
- },
- {
- 'fieldname': 'patient',
- 'label': _('Patient'),
- 'fieldtype': 'Link',
- 'options': 'Patient',
- 'width': '120'
- },
- {
- 'fieldname': 'patient_name',
- 'label': _('Patient Name'),
- 'fieldtype': 'Data',
- 'width': '120'
- },
- {
- 'fieldname': 'employee',
- 'label': _('Lab Technician'),
- 'fieldtype': 'Link',
- 'options': 'Employee',
- 'width': '120'
- },
- {
- 'fieldname': 'status',
- 'label': _('Status'),
- 'fieldtype': 'Data',
- 'width': '100'
- },
- {
- 'fieldname': 'invoiced',
- 'label': _('Invoiced'),
- 'fieldtype': 'Check',
- 'width': '100'
- },
- {
- 'fieldname': 'result_date',
- 'label': _('Result Date'),
- 'fieldtype': 'Date',
- 'width': '100'
- },
- {
- 'fieldname': 'practitioner',
- 'label': _('Requesting Practitioner'),
- 'fieldtype': 'Link',
- 'options': 'Healthcare Practitioner',
- 'width': '120'
- },
- {
- 'fieldname': 'department',
- 'label': _('Medical Department'),
- 'fieldtype': 'Link',
- 'options': 'Medical Department',
- 'width': '100'
- }
- ]
-
-def get_lab_tests(filters):
- conditions = get_conditions(filters)
- data = frappe.get_all(
- doctype='Lab Test',
- fields=['name', 'template', 'company', 'patient', 'patient_name', 'practitioner', 'employee', 'status', 'invoiced', 'result_date', 'department'],
- filters=conditions,
- order_by='submitted_date desc'
- )
- return data
-
-def get_conditions(filters):
- conditions = {
- 'docstatus': ('=', 1)
- }
-
- if filters.get('from_date') and filters.get('to_date'):
- conditions['result_date'] = ('between', (filters.get('from_date'), filters.get('to_date')))
- filters.pop('from_date')
- filters.pop('to_date')
-
- for key, value in filters.items():
- if filters.get(key):
- conditions[key] = value
-
- return conditions
-
-def get_chart_data(data):
- if not data:
- return None
-
- labels = ['Completed', 'Approved', 'Rejected']
-
- status_wise_data = {
- 'Completed': 0,
- 'Approved': 0,
- 'Rejected': 0
- }
-
- datasets = []
-
- for entry in data:
- status_wise_data[entry.status] += 1
-
- datasets.append({
- 'name': 'Lab Test Status',
- 'values': [status_wise_data.get('Completed'), status_wise_data.get('Approved'), status_wise_data.get('Rejected')]
- })
-
- chart = {
- 'data': {
- 'labels': labels,
- 'datasets': datasets
- },
- 'type': 'bar',
- 'height': 300,
- }
-
- return chart
-
-
-def get_report_summary(data):
- if not data:
- return None
-
- total_lab_tests = len(data)
- invoiced_lab_tests, unbilled_lab_tests = 0, 0
-
- for entry in data:
- if entry.invoiced:
- invoiced_lab_tests += 1
- else:
- unbilled_lab_tests += 1
-
- return [
- {
- 'value': total_lab_tests,
- 'indicator': 'Blue',
- 'label': 'Total Lab Tests',
- 'datatype': 'Int',
- },
- {
- 'value': invoiced_lab_tests,
- 'indicator': 'Green',
- 'label': 'Invoiced Lab Tests',
- 'datatype': 'Int',
- },
- {
- 'value': unbilled_lab_tests,
- 'indicator': 'Red',
- 'label': 'Unbilled Lab Tests',
- 'datatype': 'Int',
- }
- ]
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/__init__.py b/erpnext/healthcare/report/patient_appointment_analytics/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js
deleted file mode 100644
index 18d252ede13..00000000000
--- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-/* eslint-disable */
-
-frappe.query_reports['Patient Appointment Analytics'] = {
- "filters": [
- {
- fieldname: 'tree_type',
- label: __('Tree Type'),
- fieldtype: 'Select',
- options: ['Healthcare Practitioner', 'Medical Department'],
- default: 'Healthcare Practitioner',
- reqd: 1
- },
- {
- fieldname: 'status',
- label: __('Appointment Status'),
- fieldtype: 'Select',
- options:[
- {label: __('Scheduled'), value: 'Scheduled'},
- {label: __('Open'), value: 'Open'},
- {label: __('Closed'), value: 'Closed'},
- {label: __('Expired'), value: 'Expired'},
- {label: __('Cancelled'), value: 'Cancelled'}
- ]
- },
- {
- fieldname: 'appointment_type',
- label: __('Appointment Type'),
- fieldtype: 'Link',
- options: 'Appointment Type'
- },
- {
- fieldname: 'practitioner',
- label: __('Healthcare Practitioner'),
- fieldtype: 'Link',
- options: 'Healthcare Practitioner'
- },
- {
- fieldname: 'department',
- label: __('Medical Department'),
- fieldtype: 'Link',
- options: 'Medical Department'
- },
- {
- fieldname: 'from_date',
- label: __('From Date'),
- fieldtype: 'Date',
- default: frappe.defaults.get_user_default('year_start_date'),
- reqd: 1
- },
- {
- fieldname: 'to_date',
- label: __('To Date'),
- fieldtype: 'Date',
- default: frappe.defaults.get_user_default('year_end_date'),
- reqd: 1
- },
- {
- fieldname: 'range',
- label: __('Range'),
- fieldtype: 'Select',
- options:[
- {label: __('Weekly'), value: 'Weekly'},
- {label: __('Monthly'), value: 'Monthly'},
- {label: __('Quarterly'), value: 'Quarterly'},
- {label: __('Yearly'), value: 'Yearly'}
- ],
- default: 'Monthly',
- reqd: 1
- }
- ],
- after_datatable_render: function(datatable_obj) {
- $(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click();
- },
- get_datatable_options(options) {
- return Object.assign(options, {
- checkboxColumn: true,
- events: {
- onCheckRow: function(data) {
- row_name = data[2].content;
- length = data.length;
-
- row_values = data.slice(3,length-1).map(function (column) {
- return column.content;
- })
-
- entry = {
- 'name': row_name,
- 'values': row_values
- }
-
- let raw_data = frappe.query_report.chart.data;
- let new_datasets = raw_data.datasets;
-
- let found = false;
- for (let i=0; i < new_datasets.length;i++) {
- if (new_datasets[i].name == row_name) {
- found = true;
- new_datasets.splice(i,1);
- break;
- }
- }
-
- if (!found) {
- new_datasets.push(entry);
- }
-
- let new_data = {
- labels: raw_data.labels,
- datasets: new_datasets
- }
-
- setTimeout(() => {
- frappe.query_report.chart.update(new_data)
- }, 500)
-
-
- setTimeout(() => {
- frappe.query_report.chart.draw(true);
- }, 1000)
-
- frappe.query_report.raw_chart_data = new_data;
- },
- }
- })
- },
-};
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json
deleted file mode 100644
index 64750c012f1..00000000000
--- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "add_total_row": 1,
- "creation": "2020-03-02 15:13:16.273493",
- "disable_prepared_report": 0,
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 0,
- "is_standard": "Yes",
- "modified": "2020-03-02 15:13:16.273493",
- "modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Patient Appointment Analytics",
- "owner": "Administrator",
- "prepared_report": 0,
- "ref_doctype": "Patient Appointment",
- "report_name": "Patient Appointment Analytics",
- "report_type": "Script Report",
- "roles": [
- {
- "role": "Healthcare Administrator"
- },
- {
- "role": "LabTest Approver"
- },
- {
- "role": "Physician"
- },
- {
- "role": "Nursing User"
- },
- {
- "role": "Laboratory User"
- }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
deleted file mode 100644
index 1afb5da1fb4..00000000000
--- a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# 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 _, scrub
-from frappe.utils import add_days, add_to_date, flt, getdate
-from six import iteritems
-
-from erpnext.accounts.utils import get_fiscal_year
-
-
-def execute(filters=None):
- return Analytics(filters).run()
-
-class Analytics(object):
- def __init__(self, filters=None):
- """Patient Appointment Analytics Report."""
- self.filters = frappe._dict(filters or {})
- self.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
- self.get_period_date_ranges()
-
- def run(self):
- self.get_columns()
- self.get_data()
- self.get_chart_data()
-
- return self.columns, self.data, None, self.chart
-
- def get_period_date_ranges(self):
- from dateutil.relativedelta import MO, relativedelta
- from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
-
- increment = {
- 'Monthly': 1,
- 'Quarterly': 3,
- 'Half-Yearly': 6,
- 'Yearly': 12
- }.get(self.filters.range, 1)
-
- if self.filters.range in ['Monthly', 'Quarterly']:
- from_date = from_date.replace(day=1)
- elif self.filters.range == 'Yearly':
- from_date = get_fiscal_year(from_date)[1]
- else:
- from_date = from_date + relativedelta(from_date, weekday=MO(-1))
-
- self.periodic_daterange = []
- for dummy in range(1, 53):
- if self.filters.range == 'Weekly':
- period_end_date = add_days(from_date, 6)
- else:
- period_end_date = add_to_date(from_date, months=increment, days=-1)
-
- if period_end_date > to_date:
- period_end_date = to_date
-
- self.periodic_daterange.append(period_end_date)
-
- from_date = add_days(period_end_date, 1)
- if period_end_date == to_date:
- break
-
- def get_columns(self):
- self.columns = []
-
- if self.filters.tree_type == 'Healthcare Practitioner':
- self.columns.append({
- 'label': _('Healthcare Practitioner'),
- 'options': 'Healthcare Practitioner',
- 'fieldname': 'practitioner',
- 'fieldtype': 'Link',
- 'width': 200
- })
-
- elif self.filters.tree_type == 'Medical Department':
- self.columns.append({
- 'label': _('Medical Department'),
- 'fieldname': 'department',
- 'fieldtype': 'Link',
- 'options': 'Medical Department',
- 'width': 150
- })
-
- for end_date in self.periodic_daterange:
- period = self.get_period(end_date)
- self.columns.append({
- 'label': _(period),
- 'fieldname': scrub(period),
- 'fieldtype': 'Int',
- 'width': 120
- })
-
- self.columns.append({
- 'label': _('Total'),
- 'fieldname': 'total',
- 'fieldtype': 'Int',
- 'width': 120
- })
-
- def get_data(self):
- if self.filters.tree_type == 'Healthcare Practitioner':
- self.get_appointments_based_on_healthcare_practitioner()
- self.get_rows()
-
- elif self.filters.tree_type == 'Medical Department':
- self.get_appointments_based_on_medical_department()
- self.get_rows()
-
- def get_period(self, appointment_date):
- if self.filters.range == 'Weekly':
- period = 'Week ' + str(appointment_date.isocalendar()[1])
- elif self.filters.range == 'Monthly':
- period = str(self.months[appointment_date.month - 1])
- elif self.filters.range == 'Quarterly':
- period = 'Quarter ' + str(((appointment_date.month - 1) // 3) + 1)
- else:
- year = get_fiscal_year(appointment_date, company=self.filters.company)
- period = str(year[0])
-
- if getdate(self.filters.from_date).year != getdate(self.filters.to_date).year:
- period += ' ' + str(appointment_date.year)
-
- return period
-
- def get_appointments_based_on_healthcare_practitioner(self):
- filters = self.get_common_filters()
-
- self.entries = frappe.db.get_all('Patient Appointment',
- fields=['appointment_date', 'name', 'patient', 'practitioner'],
- filters=filters
- )
-
- def get_appointments_based_on_medical_department(self):
- filters = self.get_common_filters()
- if not filters.get('department'):
- filters['department'] = ('!=', '')
-
- self.entries = frappe.db.get_all('Patient Appointment',
- fields=['appointment_date', 'name', 'patient', 'practitioner', 'department'],
- filters=filters
- )
-
- def get_common_filters(self):
- filters = {}
- filters['appointment_date'] = ('between', [self.filters.from_date, self.filters.to_date])
- for entry in ['appointment_type', 'practitioner', 'department', 'status']:
- if self.filters.get(entry):
- filters[entry] = self.filters.get(entry)
-
- return filters
-
- def get_rows(self):
- self.data = []
- self.get_periodic_data()
-
- for entity, period_data in iteritems(self.appointment_periodic_data):
- if self.filters.tree_type == 'Healthcare Practitioner':
- row = {'practitioner': entity}
- elif self.filters.tree_type == 'Medical Department':
- row = {'department': entity}
-
- total = 0
- for end_date in self.periodic_daterange:
- period = self.get_period(end_date)
- amount = flt(period_data.get(period, 0.0))
- row[scrub(period)] = amount
- total += amount
-
- row['total'] = total
-
- self.data.append(row)
-
- def get_periodic_data(self):
- self.appointment_periodic_data = frappe._dict()
-
- for d in self.entries:
- period = self.get_period(d.get('appointment_date'))
- if self.filters.tree_type == 'Healthcare Practitioner':
- self.appointment_periodic_data.setdefault(d.practitioner, frappe._dict()).setdefault(period, 0.0)
- self.appointment_periodic_data[d.practitioner][period] += 1
-
- elif self.filters.tree_type == 'Medical Department':
- self.appointment_periodic_data.setdefault(d.department, frappe._dict()).setdefault(period, 0.0)
- self.appointment_periodic_data[d.department][period] += 1
-
- def get_chart_data(self):
- length = len(self.columns)
- labels = [d.get("label") for d in self.columns[1:length - 1]]
- self.chart = {
- "data": {
- 'labels': labels,
- 'datasets': []
- },
- "type": "line"
- }
diff --git a/erpnext/healthcare/setup.py b/erpnext/healthcare/setup.py
deleted file mode 100644
index 891272ddf81..00000000000
--- a/erpnext/healthcare/setup.py
+++ /dev/null
@@ -1,295 +0,0 @@
-from __future__ import unicode_literals
-import frappe
-
-from frappe import _
-from erpnext.setup.utils import insert_record
-
-def setup_healthcare():
- if frappe.db.exists('Medical Department', 'Cardiology'):
- # already setup
- return
- create_medical_departments()
- create_antibiotics()
- create_lab_test_uom()
- create_duration()
- create_dosage()
- create_healthcare_item_groups()
- create_sensitivity()
- add_healthcare_service_unit_tree_root()
- setup_patient_history_settings()
-
-def create_medical_departments():
- departments = [
- "Accident And Emergency Care" ,"Anaesthetics", "Biochemistry", "Cardiology", "Dermatology",
- "Diagnostic Imaging", "ENT", "Gastroenterology", "General Surgery", "Gynaecology",
- "Haematology", "Maternity", "Microbiology", "Nephrology", "Neurology", "Oncology",
- "Orthopaedics", "Pathology", "Physiotherapy", "Rheumatology", "Serology", "Urology"
- ]
- for department in departments:
- mediacal_department = frappe.new_doc("Medical Department")
- mediacal_department.department = _(department)
- try:
- mediacal_department.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_antibiotics():
- abt = [
- "Amoxicillin", "Ampicillin", "Bacampicillin", "Carbenicillin", "Cloxacillin", "Dicloxacillin",
- "Flucloxacillin", "Mezlocillin", "Nafcillin", "Oxacillin", "Penicillin G", "Penicillin V",
- "Piperacillin", "Pivampicillin", "Pivmecillinam", "Ticarcillin", "Cefacetrile (cephacetrile)",
- "Cefadroxil (cefadroxyl)", "Cefalexin (cephalexin)", "Cefaloglycin (cephaloglycin)",
- "Cefalonium (cephalonium)", "Cefaloridine (cephaloradine)", "Cefalotin (cephalothin)",
- "Cefapirin (cephapirin)", "Cefatrizine", "Cefazaflur", "Cefazedone", "Cefazolin (cephazolin)",
- "Cefradine (cephradine)", "Cefroxadine", "Ceftezole", "Cefaclor", "Cefamandole", "Cefmetazole",
- "Cefonicid", "Cefotetan", "Cefoxitin", "Cefprozil (cefproxil)", "Cefuroxime", "Cefuzonam",
- "Cefcapene", "Cefdaloxime", "Cefdinir", "Cefditoren", "Cefetamet", "Cefixime", "Cefmenoxime",
- "Cefodizime", "Cefotaxime", "Cefpimizole", "Cefpodoxime", "Cefteram", "Ceftibuten", "Ceftiofur",
- "Ceftiolene", "Ceftizoxime", "Ceftriaxone", "Cefoperazone", "Ceftazidime", "Cefclidine", "Cefepime",
- "Cefluprenam", "Cefoselis", "Cefozopran", "Cefpirome", "Cefquinome", "Ceftobiprole", "Ceftaroline",
- "Cefaclomezine","Cefaloram", "Cefaparole", "Cefcanel", "Cefedrolor", "Cefempidone", "Cefetrizole",
- "Cefivitril", "Cefmatilen", "Cefmepidium", "Cefovecin", "Cefoxazole", "Cefrotil", "Cefsumide",
- "Cefuracetime", "Ceftioxide", "Ceftazidime/Avibactam", "Ceftolozane/Tazobactam", "Aztreonam",
- "Imipenem", "Imipenem/cilastatin", "Doripenem", "Meropenem", "Ertapenem", "Azithromycin",
- "Erythromycin", "Clarithromycin", "Dirithromycin", "Roxithromycin", "Telithromycin", "Clindamycin",
- "Lincomycin", "Pristinamycin", "Quinupristin/dalfopristin", "Amikacin", "Gentamicin", "Kanamycin",
- "Neomycin", "Netilmicin", "Paromomycin", "Streptomycin", "Tobramycin", "Flumequine", "Nalidixic acid",
- "Oxolinic acid", "Piromidic acid", "Pipemidic acid", "Rosoxacin", "Ciprofloxacin", "Enoxacin",
- "Lomefloxacin", "Nadifloxacin", "Norfloxacin", "Ofloxacin", "Pefloxacin", "Rufloxacin", "Balofloxacin",
- "Gatifloxacin", "Grepafloxacin", "Levofloxacin", "Moxifloxacin", "Pazufloxacin", "Sparfloxacin",
- "Temafloxacin", "Tosufloxacin", "Besifloxacin", "Clinafloxacin", "Gemifloxacin",
- "Sitafloxacin", "Trovafloxacin", "Prulifloxacin", "Sulfamethizole", "Sulfamethoxazole",
- "Sulfisoxazole", "Trimethoprim-Sulfamethoxazole", "Demeclocycline", "Doxycycline", "Minocycline",
- "Oxytetracycline", "Tetracycline", "Tigecycline", "Chloramphenicol", "Metronidazole",
- "Tinidazole", "Nitrofurantoin", "Vancomycin", "Teicoplanin", "Telavancin", "Linezolid",
- "Cycloserine 2", "Rifampin", "Rifabutin", "Rifapentine", "Rifalazil", "Bacitracin", "Polymyxin B",
- "Viomycin", "Capreomycin"
- ]
-
- for a in abt:
- antibiotic = frappe.new_doc("Antibiotic")
- antibiotic.antibiotic_name = a
- try:
- antibiotic.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_lab_test_uom():
- records = [
- {"doctype": "Lab Test UOM", "name": "umol/L", "lab_test_uom": "umol/L", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "mg/L", "lab_test_uom": "mg/L", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "mg / dl", "lab_test_uom": "mg / dl", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "pg / ml", "lab_test_uom": "pg / ml", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "U/ml", "lab_test_uom": "U/ml", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "/HPF", "lab_test_uom": "/HPF", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "Million Cells / cumm", "lab_test_uom": "Million Cells / cumm", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "Lakhs Cells / cumm", "lab_test_uom": "Lakhs Cells / cumm", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "U / L", "lab_test_uom": "U / L", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "g / L", "lab_test_uom": "g / L", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "IU / ml", "lab_test_uom": "IU / ml", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "gm %", "lab_test_uom": "gm %", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "Microgram", "lab_test_uom": "Microgram", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "Micron", "lab_test_uom": "Micron", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "Cells / cumm", "lab_test_uom": "Cells / cumm", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "%", "lab_test_uom": "%", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "mm / dl", "lab_test_uom": "mm / dl", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "mm / hr", "lab_test_uom": "mm / hr", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "ulU / ml", "lab_test_uom": "ulU / ml", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "ng / ml", "lab_test_uom": "ng / ml", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "ng / dl", "lab_test_uom": "ng / dl", "uom_description": None },
- {"doctype": "Lab Test UOM", "name": "ug / dl", "lab_test_uom": "ug / dl", "uom_description": None }
- ]
-
- insert_record(records)
-
-def create_duration():
- records = [
- {"doctype": "Prescription Duration", "name": "3 Month", "number": "3", "period": "Month" },
- {"doctype": "Prescription Duration", "name": "2 Month", "number": "2", "period": "Month" },
- {"doctype": "Prescription Duration", "name": "1 Month", "number": "1", "period": "Month" },
- {"doctype": "Prescription Duration", "name": "12 Hour", "number": "12", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "11 Hour", "number": "11", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "10 Hour", "number": "10", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "9 Hour", "number": "9", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "8 Hour", "number": "8", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "7 Hour", "number": "7", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "6 Hour", "number": "6", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "5 Hour", "number": "5", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "4 Hour", "number": "4", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "3 Hour", "number": "3", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "2 Hour", "number": "2", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "1 Hour", "number": "1", "period": "Hour" },
- {"doctype": "Prescription Duration", "name": "5 Week", "number": "5", "period": "Week" },
- {"doctype": "Prescription Duration", "name": "4 Week", "number": "4", "period": "Week" },
- {"doctype": "Prescription Duration", "name": "3 Week", "number": "3", "period": "Week" },
- {"doctype": "Prescription Duration", "name": "2 Week", "number": "2", "period": "Week" },
- {"doctype": "Prescription Duration", "name": "1 Week", "number": "1", "period": "Week" },
- {"doctype": "Prescription Duration", "name": "6 Day", "number": "6", "period": "Day" },
- {"doctype": "Prescription Duration", "name": "5 Day", "number": "5", "period": "Day" },
- {"doctype": "Prescription Duration", "name": "4 Day", "number": "4", "period": "Day" },
- {"doctype": "Prescription Duration", "name": "3 Day", "number": "3", "period": "Day" },
- {"doctype": "Prescription Duration", "name": "2 Day", "number": "2", "period": "Day" },
- {"doctype": "Prescription Duration", "name": "1 Day", "number": "1", "period": "Day" }
- ]
- insert_record(records)
-
-def create_dosage():
- records = [
- {"doctype": "Prescription Dosage", "name": "1-1-1-1", "dosage": "1-1-1-1","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "0-0-1", "dosage": "0-0-1","dosage_strength":
- [{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "1-0-0", "dosage": "1-0-0","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "0-1-0", "dosage": "0-1-0","dosage_strength":
- [{"strength": "1.0","strength_time": "14:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "1-1-1", "dosage": "1-1-1","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "14:00:00"},{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "1-0-1", "dosage": "1-0-1","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "Once Bedtime", "dosage": "Once Bedtime","dosage_strength":
- [{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "5 times a day", "dosage": "5 times a day","dosage_strength":
- [{"strength": "1.0","strength_time": "5:00:00"}, {"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "QID", "dosage": "QID","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "13:00:00"},{"strength": "1.0","strength_time": "17:00:00"},{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "TID", "dosage": "TID","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "14:00:00"},{"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "BID", "dosage": "BID","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}, {"strength": "1.0","strength_time": "21:00:00"}]
- },
- {"doctype": "Prescription Dosage", "name": "Once Daily", "dosage": "Once Daily","dosage_strength":
- [{"strength": "1.0","strength_time": "9:00:00"}]
- }
- ]
- insert_record(records)
-
-def create_healthcare_item_groups():
- records = [
- {'doctype': 'Item Group', 'item_group_name': _('Laboratory'),
- 'is_group': 0, 'parent_item_group': _('All Item Groups') },
- {'doctype': 'Item Group', 'item_group_name': _('Drug'),
- 'is_group': 0, 'parent_item_group': _('All Item Groups') }
- ]
- insert_record(records)
-
-def create_sensitivity():
- records = [
- {"doctype": "Sensitivity", "sensitivity": _("Low Sensitivity")},
- {"doctype": "Sensitivity", "sensitivity": _("High Sensitivity")},
- {"doctype": "Sensitivity", "sensitivity": _("Moderate Sensitivity")},
- {"doctype": "Sensitivity", "sensitivity": _("Susceptible")},
- {"doctype": "Sensitivity", "sensitivity": _("Resistant")},
- {"doctype": "Sensitivity", "sensitivity": _("Intermediate")}
- ]
- insert_record(records)
-
-def add_healthcare_service_unit_tree_root():
- record = [
- {
- "doctype": "Healthcare Service Unit",
- "healthcare_service_unit_name": "All Healthcare Service Units",
- "is_group": 1,
- "company": get_company()
- }
- ]
- insert_record(record)
-
-def get_company():
- company = frappe.defaults.get_defaults().company
- if company:
- return company
- else:
- company = frappe.get_list("Company", limit=1)
- if company:
- return company[0].name
- return None
-
-def setup_patient_history_settings():
- import json
-
- settings = frappe.get_single('Patient History Settings')
- configuration = get_patient_history_config()
- for dt, config in configuration.items():
- settings.append("standard_doctypes", {
- "document_type": dt,
- "date_fieldname": config[0],
- "selected_fields": json.dumps(config[1])
- })
- settings.save()
-
-def get_patient_history_config():
- return {
- "Patient Encounter": ("encounter_date", [
- {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"},
- {"label": "Symptoms", "fieldname": "symptoms", "fieldtype": "Table Multiselect"},
- {"label": "Diagnosis", "fieldname": "diagnosis", "fieldtype": "Table Multiselect"},
- {"label": "Drug Prescription", "fieldname": "drug_prescription", "fieldtype": "Table"},
- {"label": "Lab Tests", "fieldname": "lab_test_prescription", "fieldtype": "Table"},
- {"label": "Clinical Procedures", "fieldname": "procedure_prescription", "fieldtype": "Table"},
- {"label": "Therapies", "fieldname": "therapies", "fieldtype": "Table"},
- {"label": "Review Details", "fieldname": "encounter_comment", "fieldtype": "Small Text"}
- ]),
- "Clinical Procedure": ("start_date", [
- {"label": "Procedure Template", "fieldname": "procedure_template", "fieldtype": "Link"},
- {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"},
- {"label": "Notes", "fieldname": "notes", "fieldtype": "Small Text"},
- {"label": "Service Unit", "fieldname": "service_unit", "fieldtype": "Healthcare Service Unit"},
- {"label": "Start Time", "fieldname": "start_time", "fieldtype": "Time"},
- {"label": "Sample", "fieldname": "sample", "fieldtype": "Link"}
- ]),
- "Lab Test": ("result_date", [
- {"label": "Test Template", "fieldname": "template", "fieldtype": "Link"},
- {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"},
- {"label": "Test Name", "fieldname": "lab_test_name", "fieldtype": "Data"},
- {"label": "Lab Technician Name", "fieldname": "employee_name", "fieldtype": "Data"},
- {"label": "Sample ID", "fieldname": "sample", "fieldtype": "Link"},
- {"label": "Normal Test Result", "fieldname": "normal_test_items", "fieldtype": "Table"},
- {"label": "Descriptive Test Result", "fieldname": "descriptive_test_items", "fieldtype": "Table"},
- {"label": "Organism Test Result", "fieldname": "organism_test_items", "fieldtype": "Table"},
- {"label": "Sensitivity Test Result", "fieldname": "sensitivity_test_items", "fieldtype": "Table"},
- {"label": "Comments", "fieldname": "lab_test_comment", "fieldtype": "Table"}
- ]),
- "Therapy Session": ("start_date", [
- {"label": "Therapy Type", "fieldname": "therapy_type", "fieldtype": "Link"},
- {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"},
- {"label": "Therapy Plan", "fieldname": "therapy_plan", "fieldtype": "Link"},
- {"label": "Duration", "fieldname": "duration", "fieldtype": "Int"},
- {"label": "Location", "fieldname": "location", "fieldtype": "Link"},
- {"label": "Healthcare Service Unit", "fieldname": "service_unit", "fieldtype": "Link"},
- {"label": "Start Time", "fieldname": "start_time", "fieldtype": "Time"},
- {"label": "Exercises", "fieldname": "exercises", "fieldtype": "Table"},
- {"label": "Total Counts Targeted", "fieldname": "total_counts_targeted", "fieldtype": "Int"},
- {"label": "Total Counts Completed", "fieldname": "total_counts_completed", "fieldtype": "Int"}
- ]),
- "Vital Signs": ("signs_date", [
- {"label": "Body Temperature", "fieldname": "temperature", "fieldtype": "Data"},
- {"label": "Heart Rate / Pulse", "fieldname": "pulse", "fieldtype": "Data"},
- {"label": "Respiratory rate", "fieldname": "respiratory_rate", "fieldtype": "Data"},
- {"label": "Tongue", "fieldname": "tongue", "fieldtype": "Select"},
- {"label": "Abdomen", "fieldname": "abdomen", "fieldtype": "Select"},
- {"label": "Reflexes", "fieldname": "reflexes", "fieldtype": "Select"},
- {"label": "Blood Pressure", "fieldname": "bp", "fieldtype": "Data"},
- {"label": "Notes", "fieldname": "vital_signs_note", "fieldtype": "Small Text"},
- {"label": "Height (In Meter)", "fieldname": "height", "fieldtype": "Float"},
- {"label": "Weight (In Kilogram)", "fieldname": "weight", "fieldtype": "Float"},
- {"label": "BMI", "fieldname": "bmi", "fieldtype": "Float"}
- ]),
- "Inpatient Medication Order": ("start_date", [
- {"label": "Healthcare Practitioner", "fieldname": "practitioner", "fieldtype": "Link"},
- {"label": "Start Date", "fieldname": "start_date", "fieldtype": "Date"},
- {"label": "End Date", "fieldname": "end_date", "fieldtype": "Date"},
- {"label": "Medication Orders", "fieldname": "medication_orders", "fieldtype": "Table"},
- {"label": "Total Orders", "fieldname": "total_orders", "fieldtype": "Float"}
- ])
- }
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
deleted file mode 100644
index cae3008ca82..00000000000
--- a/erpnext/healthcare/utils.py
+++ /dev/null
@@ -1,792 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, earthians and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-
-import json
-import math
-
-import frappe
-from frappe import _
-from frappe.utils import cstr, rounded, time_diff_in_hours
-from frappe.utils.formatters import format_value
-
-from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
-from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
-
-
-@frappe.whitelist()
-def get_healthcare_services_to_invoice(patient, company):
- patient = frappe.get_doc('Patient', patient)
- items_to_invoice = []
- if patient:
- validate_customer_created(patient)
- # Customer validated, build a list of billable services
- items_to_invoice += get_appointments_to_invoice(patient, company)
- items_to_invoice += get_encounters_to_invoice(patient, company)
- items_to_invoice += get_lab_tests_to_invoice(patient, company)
- items_to_invoice += get_clinical_procedures_to_invoice(patient, company)
- items_to_invoice += get_inpatient_services_to_invoice(patient, company)
- items_to_invoice += get_therapy_plans_to_invoice(patient, company)
- items_to_invoice += get_therapy_sessions_to_invoice(patient, company)
-
- return items_to_invoice
-
-
-def validate_customer_created(patient):
- if not frappe.db.get_value('Patient', patient.name, 'customer'):
- msg = _("Please set a Customer linked to the Patient")
- msg += " {0} ".format(patient.name)
- frappe.throw(msg, title=_('Customer Not Found'))
-
-
-def get_appointments_to_invoice(patient, company):
- appointments_to_invoice = []
- patient_appointments = frappe.get_list(
- 'Patient Appointment',
- fields = '*',
- filters = {'patient': patient.name, 'company': company, 'invoiced': 0, 'status': ['not in', 'Cancelled']},
- order_by = 'appointment_date'
- )
-
- for appointment in patient_appointments:
- # Procedure Appointments
- if appointment.procedure_template:
- if frappe.db.get_value('Clinical Procedure Template', appointment.procedure_template, 'is_billable'):
- appointments_to_invoice.append({
- 'reference_type': 'Patient Appointment',
- 'reference_name': appointment.name,
- 'service': appointment.procedure_template
- })
- # Consultation Appointments, should check fee validity
- else:
- if frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') and \
- frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}):
- continue # Skip invoicing, fee validty present
- practitioner_charge = 0
- income_account = None
- service_item = None
- if appointment.practitioner:
- details = get_service_item_and_practitioner_charge(appointment)
- service_item = details.get('service_item')
- practitioner_charge = details.get('practitioner_charge')
- income_account = get_income_account(appointment.practitioner, appointment.company)
- appointments_to_invoice.append({
- 'reference_type': 'Patient Appointment',
- 'reference_name': appointment.name,
- 'service': service_item,
- 'rate': practitioner_charge,
- 'income_account': income_account
- })
-
- return appointments_to_invoice
-
-
-def get_encounters_to_invoice(patient, company):
- if not isinstance(patient, str):
- patient = patient.name
- encounters_to_invoice = []
- encounters = frappe.get_list(
- 'Patient Encounter',
- fields=['*'],
- filters={'patient': patient, 'company': company, 'invoiced': False, 'docstatus': 1}
- )
- if encounters:
- for encounter in encounters:
- if not encounter.appointment:
- practitioner_charge = 0
- income_account = None
- service_item = None
- if encounter.practitioner:
- if encounter.inpatient_record and \
- frappe.db.get_single_value('Healthcare Settings', 'do_not_bill_inpatient_encounters'):
- continue
-
- details = get_service_item_and_practitioner_charge(encounter)
- service_item = details.get('service_item')
- practitioner_charge = details.get('practitioner_charge')
- income_account = get_income_account(encounter.practitioner, encounter.company)
-
- encounters_to_invoice.append({
- 'reference_type': 'Patient Encounter',
- 'reference_name': encounter.name,
- 'service': service_item,
- 'rate': practitioner_charge,
- 'income_account': income_account
- })
-
- return encounters_to_invoice
-
-
-def get_lab_tests_to_invoice(patient, company):
- lab_tests_to_invoice = []
- lab_tests = frappe.get_list(
- 'Lab Test',
- fields=['name', 'template'],
- filters={'patient': patient.name, 'company': company, 'invoiced': False, 'docstatus': 1}
- )
- for lab_test in lab_tests:
- item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.template, ['item', 'is_billable'])
- if is_billable:
- lab_tests_to_invoice.append({
- 'reference_type': 'Lab Test',
- 'reference_name': lab_test.name,
- 'service': item
- })
-
- lab_prescriptions = frappe.db.sql(
- '''
- SELECT
- lp.name, lp.lab_test_code
- FROM
- `tabPatient Encounter` et, `tabLab Prescription` lp
- WHERE
- et.patient=%s
- and lp.parent=et.name
- and lp.lab_test_created=0
- and lp.invoiced=0
- ''', (patient.name), as_dict=1)
-
- for prescription in lab_prescriptions:
- item, is_billable = frappe.get_cached_value('Lab Test Template', prescription.lab_test_code, ['item', 'is_billable'])
- if prescription.lab_test_code and is_billable:
- lab_tests_to_invoice.append({
- 'reference_type': 'Lab Prescription',
- 'reference_name': prescription.name,
- 'service': item
- })
-
- return lab_tests_to_invoice
-
-
-def get_clinical_procedures_to_invoice(patient, company):
- clinical_procedures_to_invoice = []
- procedures = frappe.get_list(
- 'Clinical Procedure',
- fields='*',
- filters={'patient': patient.name, 'company': company, 'invoiced': False}
- )
- for procedure in procedures:
- if not procedure.appointment:
- item, is_billable = frappe.get_cached_value('Clinical Procedure Template', procedure.procedure_template, ['item', 'is_billable'])
- if procedure.procedure_template and is_billable:
- clinical_procedures_to_invoice.append({
- 'reference_type': 'Clinical Procedure',
- 'reference_name': procedure.name,
- 'service': item
- })
-
- # consumables
- if procedure.invoice_separately_as_consumables and procedure.consume_stock \
- and procedure.status == 'Completed' and not procedure.consumption_invoiced:
-
- service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
- if not service_item:
- frappe.throw(_('Please configure Clinical Procedure Consumable Item in {0}').format(
- frappe.utils.get_link_to_form('Healthcare Settings', 'Healthcare Settings')),
- title=_('Missing Configuration'))
-
- clinical_procedures_to_invoice.append({
- 'reference_type': 'Clinical Procedure',
- 'reference_name': procedure.name,
- 'service': service_item,
- 'rate': procedure.consumable_total_amount,
- 'description': procedure.consumption_details
- })
-
- procedure_prescriptions = frappe.db.sql(
- '''
- SELECT
- pp.name, pp.procedure
- FROM
- `tabPatient Encounter` et, `tabProcedure Prescription` pp
- WHERE
- et.patient=%s
- and pp.parent=et.name
- and pp.procedure_created=0
- and pp.invoiced=0
- and pp.appointment_booked=0
- ''', (patient.name), as_dict=1)
-
- for prescription in procedure_prescriptions:
- item, is_billable = frappe.get_cached_value('Clinical Procedure Template', prescription.procedure, ['item', 'is_billable'])
- if is_billable:
- clinical_procedures_to_invoice.append({
- 'reference_type': 'Procedure Prescription',
- 'reference_name': prescription.name,
- 'service': item
- })
-
- return clinical_procedures_to_invoice
-
-
-def get_inpatient_services_to_invoice(patient, company):
- services_to_invoice = []
- inpatient_services = frappe.db.sql(
- '''
- SELECT
- io.*
- FROM
- `tabInpatient Record` ip, `tabInpatient Occupancy` io
- WHERE
- ip.patient=%s
- and ip.company=%s
- and io.parent=ip.name
- and io.left=1
- and io.invoiced=0
- ''', (patient.name, company), as_dict=1)
-
- for inpatient_occupancy in inpatient_services:
- service_unit_type = frappe.db.get_value('Healthcare Service Unit', inpatient_occupancy.service_unit, 'service_unit_type')
- service_unit_type = frappe.get_cached_doc('Healthcare Service Unit Type', service_unit_type)
- if service_unit_type and service_unit_type.is_billable:
- hours_occupied = time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in)
- qty = 0.5
- if hours_occupied > 0:
- actual_qty = hours_occupied / service_unit_type.no_of_hours
- floor = math.floor(actual_qty)
- decimal_part = actual_qty - floor
- if decimal_part > 0.5:
- qty = rounded(floor + 1, 1)
- elif decimal_part < 0.5 and decimal_part > 0:
- qty = rounded(floor + 0.5, 1)
- if qty <= 0:
- qty = 0.5
- services_to_invoice.append({
- 'reference_type': 'Inpatient Occupancy',
- 'reference_name': inpatient_occupancy.name,
- 'service': service_unit_type.item, 'qty': qty
- })
-
- return services_to_invoice
-
-
-def get_therapy_plans_to_invoice(patient, company):
- therapy_plans_to_invoice = []
- therapy_plans = frappe.get_list(
- 'Therapy Plan',
- fields=['therapy_plan_template', 'name'],
- filters={
- 'patient': patient.name,
- 'invoiced': 0,
- 'company': company,
- 'therapy_plan_template': ('!=', '')
- }
- )
- for plan in therapy_plans:
- therapy_plans_to_invoice.append({
- 'reference_type': 'Therapy Plan',
- 'reference_name': plan.name,
- 'service': frappe.db.get_value('Therapy Plan Template', plan.therapy_plan_template, 'linked_item')
- })
-
- return therapy_plans_to_invoice
-
-
-def get_therapy_sessions_to_invoice(patient, company):
- therapy_sessions_to_invoice = []
- therapy_plans = frappe.db.get_all('Therapy Plan', {'therapy_plan_template': ('!=', '')})
- therapy_plans_created_from_template = []
- for entry in therapy_plans:
- therapy_plans_created_from_template.append(entry.name)
-
- therapy_sessions = frappe.get_list(
- 'Therapy Session',
- fields='*',
- filters={
- 'patient': patient.name,
- 'invoiced': 0,
- 'company': company,
- 'therapy_plan': ('not in', therapy_plans_created_from_template)
- }
- )
- for therapy in therapy_sessions:
- if not therapy.appointment:
- if therapy.therapy_type and frappe.db.get_value('Therapy Type', therapy.therapy_type, 'is_billable'):
- therapy_sessions_to_invoice.append({
- 'reference_type': 'Therapy Session',
- 'reference_name': therapy.name,
- 'service': frappe.db.get_value('Therapy Type', therapy.therapy_type, 'item')
- })
-
- return therapy_sessions_to_invoice
-
-@frappe.whitelist()
-def get_service_item_and_practitioner_charge(doc):
- if isinstance(doc, str):
- doc = json.loads(doc)
- doc = frappe.get_doc(doc)
-
- service_item = None
- practitioner_charge = None
- department = doc.medical_department if doc.doctype == 'Patient Encounter' else doc.department
-
- is_inpatient = doc.inpatient_record
-
- if doc.get('appointment_type'):
- service_item, practitioner_charge = get_appointment_type_service_item(doc.appointment_type, department, is_inpatient)
-
- if not service_item and not practitioner_charge:
- service_item, practitioner_charge = get_practitioner_service_item(doc.practitioner, is_inpatient)
- if not service_item:
- service_item = get_healthcare_service_item(is_inpatient)
-
- if not service_item:
- throw_config_service_item(is_inpatient)
-
- if not practitioner_charge:
- throw_config_practitioner_charge(is_inpatient, doc.practitioner)
-
- return {'service_item': service_item, 'practitioner_charge': practitioner_charge}
-
-
-def get_appointment_type_service_item(appointment_type, department, is_inpatient):
- from erpnext.healthcare.doctype.appointment_type.appointment_type import (
- get_service_item_based_on_department,
- )
-
- item_list = get_service_item_based_on_department(appointment_type, department)
- service_item = None
- practitioner_charge = None
-
- if item_list:
- if is_inpatient:
- service_item = item_list.get('inpatient_visit_charge_item')
- practitioner_charge = item_list.get('inpatient_visit_charge')
- else:
- service_item = item_list.get('op_consulting_charge_item')
- practitioner_charge = item_list.get('op_consulting_charge')
-
- return service_item, practitioner_charge
-
-
-def throw_config_service_item(is_inpatient):
- service_item_label = _('Out Patient Consulting Charge Item')
- if is_inpatient:
- service_item_label = _('Inpatient Visit Charge Item')
-
- msg = _(('Please Configure {0} in ').format(service_item_label) \
- + '''Healthcare Settings ''')
- frappe.throw(msg, title=_('Missing Configuration'))
-
-
-def throw_config_practitioner_charge(is_inpatient, practitioner):
- charge_name = _('OP Consulting Charge')
- if is_inpatient:
- charge_name = _('Inpatient Visit Charge')
-
- msg = _(('Please Configure {0} for Healthcare Practitioner').format(charge_name) \
- + ''' {0} '''.format(practitioner))
- frappe.throw(msg, title=_('Missing Configuration'))
-
-
-def get_practitioner_service_item(practitioner, is_inpatient):
- service_item = None
- practitioner_charge = None
-
- if is_inpatient:
- service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['inpatient_visit_charge_item', 'inpatient_visit_charge'])
- else:
- service_item, practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, ['op_consulting_charge_item', 'op_consulting_charge'])
-
- return service_item, practitioner_charge
-
-
-def get_healthcare_service_item(is_inpatient):
- service_item = None
-
- if is_inpatient:
- service_item = frappe.db.get_single_value('Healthcare Settings', 'inpatient_visit_charge_item')
- else:
- service_item = frappe.db.get_single_value('Healthcare Settings', 'op_consulting_charge_item')
-
- return service_item
-
-
-def get_practitioner_charge(practitioner, is_inpatient):
- if is_inpatient:
- practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'inpatient_visit_charge')
- else:
- practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'op_consulting_charge')
- if practitioner_charge:
- return practitioner_charge
- return False
-
-
-def manage_invoice_submit_cancel(doc, method):
- if doc.items:
- for item in doc.items:
- if item.get('reference_dt') and item.get('reference_dn'):
- if frappe.get_meta(item.reference_dt).has_field('invoiced'):
- set_invoiced(item, method, doc.name)
-
- if method=='on_submit' and frappe.db.get_single_value('Healthcare Settings', 'create_lab_test_on_si_submit'):
- create_multiple('Sales Invoice', doc.name)
-
-
-def set_invoiced(item, method, ref_invoice=None):
- invoiced = False
- if method=='on_submit':
- validate_invoiced_on_submit(item)
- invoiced = True
-
- if item.reference_dt == 'Clinical Procedure':
- service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
- if service_item == item.item_code:
- frappe.db.set_value(item.reference_dt, item.reference_dn, 'consumption_invoiced', invoiced)
- else:
- frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced)
- else:
- frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced)
-
- if item.reference_dt == 'Patient Appointment':
- if frappe.db.get_value('Patient Appointment', item.reference_dn, 'procedure_template'):
- dt_from_appointment = 'Clinical Procedure'
- else:
- dt_from_appointment = 'Patient Encounter'
- manage_doc_for_appointment(dt_from_appointment, item.reference_dn, invoiced)
-
- elif item.reference_dt == 'Lab Prescription':
- manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Lab Test', 'lab_test_created')
-
- elif item.reference_dt == 'Procedure Prescription':
- manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Clinical Procedure', 'procedure_created')
-
-
-def validate_invoiced_on_submit(item):
- if item.reference_dt == 'Clinical Procedure' and \
- frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item') == item.item_code:
- is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'consumption_invoiced')
- else:
- is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'invoiced')
- if is_invoiced:
- frappe.throw(_('The item referenced by {0} - {1} is already invoiced').format(
- item.reference_dt, item.reference_dn))
-
-
-def manage_prescriptions(invoiced, ref_dt, ref_dn, dt, created_check_field):
- created = frappe.db.get_value(ref_dt, ref_dn, created_check_field)
- if created:
- # Fetch the doc created for the prescription
- doc_created = frappe.db.get_value(dt, {'prescription': ref_dn})
- frappe.db.set_value(dt, doc_created, 'invoiced', invoiced)
-
-
-def check_fee_validity(appointment):
- if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
- return
-
- validity = frappe.db.exists('Fee Validity', {
- 'practitioner': appointment.practitioner,
- 'patient': appointment.patient,
- 'valid_till': ('>=', appointment.appointment_date)
- })
- if not validity:
- return
-
- validity = frappe.get_doc('Fee Validity', validity)
- return validity
-
-
-def manage_fee_validity(appointment):
- fee_validity = check_fee_validity(appointment)
-
- if fee_validity:
- if appointment.status == 'Cancelled' and fee_validity.visited > 0:
- fee_validity.visited -= 1
- frappe.db.delete('Fee Validity Reference', {'appointment': appointment.name})
- elif fee_validity.status == 'Completed':
- return
- else:
- fee_validity.visited += 1
- fee_validity.append('ref_appointments', {
- 'appointment': appointment.name
- })
- fee_validity.save(ignore_permissions=True)
- else:
- fee_validity = create_fee_validity(appointment)
- return fee_validity
-
-
-def manage_doc_for_appointment(dt_from_appointment, appointment, invoiced):
- dn_from_appointment = frappe.db.get_value(
- dt_from_appointment,
- filters={'appointment': appointment}
- )
- if dn_from_appointment:
- frappe.db.set_value(dt_from_appointment, dn_from_appointment, 'invoiced', invoiced)
-
-
-@frappe.whitelist()
-def get_drugs_to_invoice(encounter):
- encounter = frappe.get_doc('Patient Encounter', encounter)
- if encounter:
- patient = frappe.get_doc('Patient', encounter.patient)
- if patient:
- if patient.customer:
- items_to_invoice = []
- for drug_line in encounter.drug_prescription:
- if drug_line.drug_code:
- qty = 1
- if frappe.db.get_value('Item', drug_line.drug_code, 'stock_uom') == 'Nos':
- qty = drug_line.get_quantity()
-
- description = ''
- if drug_line.dosage and drug_line.period:
- description = _('{0} for {1}').format(drug_line.dosage, drug_line.period)
-
- items_to_invoice.append({
- 'drug_code': drug_line.drug_code,
- 'quantity': qty,
- 'description': description
- })
- return items_to_invoice
- else:
- validate_customer_created(patient)
-
-
-@frappe.whitelist()
-def get_children(doctype, parent=None, company=None, is_root=False):
- parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_')
- fields = [
- 'name as value',
- 'is_group as expandable',
- 'lft',
- 'rgt'
- ]
-
- filters = [["ifnull(`{0}`,'')".format(parent_fieldname),
- '=', '' if is_root else parent]]
-
- if is_root:
- fields += ['service_unit_type'] if doctype == 'Healthcare Service Unit' else []
- filters.append(['company', '=', company])
- else:
- fields += ['service_unit_type', 'allow_appointments', 'inpatient_occupancy',
- 'occupancy_status'] if doctype == 'Healthcare Service Unit' else []
- fields += [parent_fieldname + ' as parent']
-
- service_units = frappe.get_list(doctype, fields=fields, filters=filters)
- for each in service_units:
- if each['expandable'] == 1: # group node
- available_count = frappe.db.count('Healthcare Service Unit', filters={
- 'parent_healthcare_service_unit': each['value'],
- 'inpatient_occupancy': 1})
-
- if available_count > 0:
- occupied_count = frappe.db.count('Healthcare Service Unit', {
- 'parent_healthcare_service_unit': each['value'],
- 'inpatient_occupancy': 1,
- 'occupancy_status': 'Occupied'})
- # set occupancy status of group node
- each['occupied_of_available'] = str(
- occupied_count) + ' Occupied of ' + str(available_count)
-
- return service_units
-
-
-@frappe.whitelist()
-def get_patient_vitals(patient, from_date=None, to_date=None):
- if not patient: return
-
- vitals = frappe.db.get_all('Vital Signs', filters={
- 'docstatus': 1,
- 'patient': patient
- }, order_by='signs_date, signs_time', fields=['*'])
-
- if len(vitals):
- return vitals
- return False
-
-
-@frappe.whitelist()
-def render_docs_as_html(docs):
- # docs key value pair {doctype: docname}
- docs_html = ""
- for doc in docs:
- docs_html += render_doc_as_html(doc['doctype'], doc['docname'])['html'] + ' '
- return {'html': docs_html}
-
-
-@frappe.whitelist()
-def render_doc_as_html(doctype, docname, exclude_fields = []):
- """
- Render document as HTML
- """
-
- doc = frappe.get_doc(doctype, docname)
- meta = frappe.get_meta(doctype)
- doc_html = section_html = section_label = html = ""
- sec_on = has_data = False
- col_on = 0
-
- for df in meta.fields:
- # on section break append previous section and html to doc html
- if df.fieldtype == "Section Break":
- if has_data and col_on and sec_on:
- doc_html += section_html + html + "
"
-
- elif has_data and not col_on and sec_on:
- doc_html += """
-
-
-
- """.format(section_label, section_html, html)
-
- # close divs for columns
- while col_on:
- doc_html += " "
- col_on -= 1
-
- sec_on = True
- has_data = False
- col_on = 0
- section_html = html = ""
-
- if df.label:
- section_label = df.label
- continue
-
- # on column break append html to section html or doc html
- if df.fieldtype == "Column Break":
- if sec_on and not col_on and has_data:
- section_html += """
-
+ Interview Feedback for Interview {{ name }} is not submitted yet. Please submit your feedback. Thank you, good day!
+
diff --git a/erpnext/hr/doctype/interview/interview_list.js b/erpnext/hr/doctype/interview/interview_list.js
new file mode 100644
index 00000000000..b1f072f0d4b
--- /dev/null
+++ b/erpnext/hr/doctype/interview/interview_list.js
@@ -0,0 +1,12 @@
+frappe.listview_settings['Interview'] = {
+ has_indicator_for_draft: 1,
+ get_indicator: function(doc) {
+ let status_color = {
+ 'Pending': 'orange',
+ 'Under Review': 'blue',
+ 'Cleared': 'green',
+ 'Rejected': 'red',
+ };
+ return [__(doc.status), status_color[doc.status], 'status,=,'+doc.status];
+ }
+};
diff --git a/erpnext/hr/doctype/interview/interview_reminder_notification_template.html b/erpnext/hr/doctype/interview/interview_reminder_notification_template.html
new file mode 100644
index 00000000000..76de46e28db
--- /dev/null
+++ b/erpnext/hr/doctype/interview/interview_reminder_notification_template.html
@@ -0,0 +1,5 @@
+
+ Interview: {{name}} is scheduled on {{scheduled_on}} from {{from_time}} to {{to_time}}
+
diff --git a/erpnext/hr/doctype/interview/test_interview.py b/erpnext/hr/doctype/interview/test_interview.py
new file mode 100644
index 00000000000..4612e17db03
--- /dev/null
+++ b/erpnext/hr/doctype/interview/test_interview.py
@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import datetime
+import os
+import unittest
+
+import frappe
+from frappe import _
+from frappe.core.doctype.user_permission.test_user_permission import create_user
+from frappe.utils import add_days, getdate, nowtime
+
+from erpnext.hr.doctype.designation.test_designation import create_designation
+from erpnext.hr.doctype.interview.interview import DuplicateInterviewRoundError
+from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant
+
+
+class TestInterview(unittest.TestCase):
+ def test_validations_for_designation(self):
+ job_applicant = create_job_applicant()
+ interview = create_interview_and_dependencies(job_applicant.name, designation='_Test_Sales_manager', save=0)
+ self.assertRaises(DuplicateInterviewRoundError, interview.save)
+
+ def test_notification_on_rescheduling(self):
+ job_applicant = create_job_applicant()
+ interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -4))
+
+ previous_scheduled_date = interview.scheduled_on
+ frappe.db.sql("DELETE FROM `tabEmail Queue`")
+
+ interview.reschedule_interview(add_days(getdate(previous_scheduled_date), 2),
+ from_time=nowtime(), to_time=nowtime())
+ interview.reload()
+
+ self.assertEqual(interview.scheduled_on, add_days(getdate(previous_scheduled_date), 2))
+
+ notification = frappe.get_all("Email Queue", filters={"message": ("like", "%Your Interview session is rescheduled from%")})
+ self.assertIsNotNone(notification)
+
+ def test_notification_for_scheduling(self):
+ from erpnext.hr.doctype.interview.interview import send_interview_reminder
+
+ setup_reminder_settings()
+
+ job_applicant = create_job_applicant()
+ scheduled_on = datetime.datetime.now() + datetime.timedelta(minutes=10)
+
+ interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=scheduled_on)
+
+ frappe.db.sql("DELETE FROM `tabEmail Queue`")
+ send_interview_reminder()
+
+ interview.reload()
+
+ email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
+ self.assertTrue("Subject: Interview Reminder" in email_queue[0].message)
+
+ def test_notification_for_feedback_submission(self):
+ from erpnext.hr.doctype.interview.interview import send_daily_feedback_reminder
+
+ setup_reminder_settings()
+
+ job_applicant = create_job_applicant()
+ scheduled_on = add_days(getdate(), -4)
+ create_interview_and_dependencies(job_applicant.name, scheduled_on=scheduled_on)
+
+ frappe.db.sql("DELETE FROM `tabEmail Queue`")
+ send_daily_feedback_reminder()
+
+ email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
+ self.assertTrue("Subject: Interview Feedback Reminder" in email_queue[0].message)
+
+ def tearDown(self):
+ frappe.db.rollback()
+
+
+def create_interview_and_dependencies(job_applicant, scheduled_on=None, from_time=None, to_time=None, designation=None, save=1):
+ if designation:
+ designation=create_designation(designation_name = "_Test_Sales_manager").name
+
+ interviewer_1 = create_user("test_interviewer1@example.com", "Interviewer")
+ interviewer_2 = create_user("test_interviewer2@example.com", "Interviewer")
+
+ interview_round = create_interview_round(
+ "Technical Round", ["Python", "JS"],
+ designation=designation, save=True
+ )
+
+ interview = frappe.new_doc("Interview")
+ interview.interview_round = interview_round.name
+ interview.job_applicant = job_applicant
+ interview.scheduled_on = scheduled_on or getdate()
+ interview.from_time = from_time or nowtime()
+ interview.to_time = to_time or nowtime()
+
+ interview.append("interview_details", {"interviewer": interviewer_1.name})
+ interview.append("interview_details", {"interviewer": interviewer_2.name})
+
+ if save:
+ interview.save()
+
+ return interview
+
+def create_interview_round(name, skill_set, interviewers=[], designation=None, save=True):
+ create_skill_set(skill_set)
+ interview_round = frappe.new_doc("Interview Round")
+ interview_round.round_name = name
+ interview_round.interview_type = create_interview_type()
+ interview_round.expected_average_rating = 4
+ if designation:
+ interview_round.designation = designation
+
+ for skill in skill_set:
+ interview_round.append("expected_skill_set", {"skill": skill})
+
+ for interviewer in interviewers:
+ interview_round.append("interviewer", {
+ "user": interviewer
+ })
+
+ if save:
+ interview_round.save()
+
+ return interview_round
+
+def create_skill_set(skill_set):
+ for skill in skill_set:
+ if not frappe.db.exists("Skill", skill):
+ doc = frappe.new_doc("Skill")
+ doc.skill_name = skill
+ doc.save()
+
+def create_interview_type(name="test_interview_type"):
+ if frappe.db.exists("Interview Type", name):
+ return frappe.get_doc("Interview Type", name).name
+ else:
+ doc = frappe.new_doc("Interview Type")
+ doc.name = name
+ doc.description = "_Test_Description"
+ doc.save()
+
+ return doc.name
+
+def setup_reminder_settings():
+ if not frappe.db.exists('Email Template', _('Interview Reminder')):
+ base_path = frappe.get_app_path('erpnext', 'hr', 'doctype')
+ response = frappe.read_file(os.path.join(base_path, 'interview/interview_reminder_notification_template.html'))
+
+ frappe.get_doc({
+ 'doctype': 'Email Template',
+ 'name': _('Interview Reminder'),
+ 'response': response,
+ 'subject': _('Interview Reminder'),
+ 'owner': frappe.session.user,
+ }).insert(ignore_permissions=True)
+
+ if not frappe.db.exists('Email Template', _('Interview Feedback Reminder')):
+ base_path = frappe.get_app_path('erpnext', 'hr', 'doctype')
+ response = frappe.read_file(os.path.join(base_path, 'interview/interview_feedback_reminder_template.html'))
+
+ frappe.get_doc({
+ 'doctype': 'Email Template',
+ 'name': _('Interview Feedback Reminder'),
+ 'response': response,
+ 'subject': _('Interview Feedback Reminder'),
+ 'owner': frappe.session.user,
+ }).insert(ignore_permissions=True)
+
+ hr_settings = frappe.get_doc('HR Settings')
+ hr_settings.interview_reminder_template = _('Interview Reminder')
+ hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder')
+ hr_settings.save()
diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/__init__.py b/erpnext/hr/doctype/interview_detail/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/clinical_procedure_item/__init__.py
rename to erpnext/hr/doctype/interview_detail/__init__.py
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js b/erpnext/hr/doctype/interview_detail/interview_detail.js
similarity index 79%
rename from erpnext/buying/doctype/supplier_item_group/supplier_item_group.js
rename to erpnext/hr/doctype/interview_detail/interview_detail.js
index f7da90d98d6..88518ca4cc1 100644
--- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.js
+++ b/erpnext/hr/doctype/interview_detail/interview_detail.js
@@ -1,7 +1,7 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Supplier Item Group', {
+frappe.ui.form.on('Interview Detail', {
// refresh: function(frm) {
// }
diff --git a/erpnext/hr/doctype/interview_detail/interview_detail.json b/erpnext/hr/doctype/interview_detail/interview_detail.json
new file mode 100644
index 00000000000..b5b49c0993a
--- /dev/null
+++ b/erpnext/hr/doctype/interview_detail/interview_detail.json
@@ -0,0 +1,74 @@
+{
+ "actions": [],
+ "creation": "2021-04-12 16:24:10.382863",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "interviewer",
+ "interview_feedback",
+ "average_rating",
+ "result",
+ "column_break_4",
+ "comments"
+ ],
+ "fields": [
+ {
+ "fieldname": "interviewer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Interviewer",
+ "options": "User"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "interview_feedback",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Interview Feedback",
+ "options": "Interview Feedback",
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "average_rating",
+ "fieldtype": "Rating",
+ "in_list_view": 1,
+ "label": "Average Rating",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fetch_from": "interview_feedback.feedback",
+ "fieldname": "comments",
+ "fieldtype": "Text",
+ "label": "Comments",
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "result",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Result",
+ "options": "\nCleared\nRejected",
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-09-29 13:13:25.865063",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Interview Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/body_part_link/body_part_link.py b/erpnext/hr/doctype/interview_detail/interview_detail.py
similarity index 65%
rename from erpnext/healthcare/doctype/body_part_link/body_part_link.py
rename to erpnext/hr/doctype/interview_detail/interview_detail.py
index 07488f01177..8be3d34fad3 100644
--- a/erpnext/healthcare/doctype/body_part_link/body_part_link.py
+++ b/erpnext/hr/doctype/interview_detail/interview_detail.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
@@ -8,5 +8,5 @@ from __future__ import unicode_literals
from frappe.model.document import Document
-class BodyPartLink(Document):
+class InterviewDetail(Document):
pass
diff --git a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py b/erpnext/hr/doctype/interview_detail/test_interview_detail.py
similarity index 80%
rename from erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py
rename to erpnext/hr/doctype/interview_detail/test_interview_detail.py
index 55ba85ef2d6..a29dffff779 100644
--- a/erpnext/buying/doctype/supplier_item_group/test_supplier_item_group.py
+++ b/erpnext/hr/doctype/interview_detail/test_interview_detail.py
@@ -7,5 +7,5 @@ from __future__ import unicode_literals
import unittest
-class TestSupplierItemGroup(unittest.TestCase):
+class TestInterviewDetail(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/__init__.py b/erpnext/hr/doctype/interview_feedback/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/clinical_procedure_template/__init__.py
rename to erpnext/hr/doctype/interview_feedback/__init__.py
diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.js b/erpnext/hr/doctype/interview_feedback/interview_feedback.js
new file mode 100644
index 00000000000..dec559fceae
--- /dev/null
+++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.js
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Interview Feedback', {
+ onload: function(frm) {
+ frm.ignore_doctypes_on_cancel_all = ['Interview'];
+
+ frm.set_query('interview', function() {
+ return {
+ filters: {
+ docstatus: ['!=', 2]
+ }
+ };
+ });
+ },
+
+ interview_round: function(frm) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.interview.interview.get_expected_skill_set',
+ args: {
+ interview_round: frm.doc.interview_round
+ },
+ callback: function(r) {
+ frm.set_value('skill_assessment', r.message);
+ }
+ });
+ },
+
+ interview: function(frm) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.interview_feedback.interview_feedback.get_applicable_interviewers',
+ args: {
+ interview: frm.doc.interview || ''
+ },
+ callback: function(r) {
+ frm.set_query('interviewer', function() {
+ return {
+ filters: {
+ name: ['in', r.message]
+ }
+ };
+ });
+ }
+ });
+
+ },
+
+ interviewer: function(frm) {
+ if (!frm.doc.interview) {
+ frappe.throw(__('Select Interview first'));
+ frm.set_value('interviewer', '');
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.json b/erpnext/hr/doctype/interview_feedback/interview_feedback.json
new file mode 100644
index 00000000000..6a2f7e86969
--- /dev/null
+++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.json
@@ -0,0 +1,171 @@
+{
+ "actions": [],
+ "autoname": "HR-INT-FEED-.####",
+ "creation": "2021-04-12 17:03:13.833285",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "details_section",
+ "interview",
+ "interview_round",
+ "job_applicant",
+ "column_break_3",
+ "interviewer",
+ "result",
+ "section_break_4",
+ "skill_assessment",
+ "average_rating",
+ "section_break_7",
+ "feedback",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "interview",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Interview",
+ "options": "Interview",
+ "reqd": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fetch_from": "interview.interview_round",
+ "fieldname": "interview_round",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Interview Round",
+ "options": "Interview Round",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "interviewer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Interviewer",
+ "options": "User",
+ "reqd": 1
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "label": "Skill Assessment"
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "skill_assessment",
+ "fieldtype": "Table",
+ "options": "Skill Assessment",
+ "reqd": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "average_rating",
+ "fieldtype": "Rating",
+ "in_list_view": 1,
+ "label": "Average Rating",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
+ "label": "Feedback"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Interview Feedback",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "fieldname": "feedback",
+ "fieldtype": "Text"
+ },
+ {
+ "fieldname": "result",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Result",
+ "options": "\nCleared\nRejected",
+ "reqd": 1
+ },
+ {
+ "fieldname": "details_section",
+ "fieldtype": "Section Break",
+ "label": "Details"
+ },
+ {
+ "fetch_from": "interview.job_applicant",
+ "fieldname": "job_applicant",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Job Applicant",
+ "options": "Job Applicant",
+ "read_only": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-09-30 13:30:49.955352",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Interview Feedback",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1
+ },
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Interviewer",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "interviewer",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/interview_feedback/interview_feedback.py b/erpnext/hr/doctype/interview_feedback/interview_feedback.py
new file mode 100644
index 00000000000..1c5a4948f24
--- /dev/null
+++ b/erpnext/hr/doctype/interview_feedback/interview_feedback.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import flt, get_link_to_form, getdate
+
+
+class InterviewFeedback(Document):
+ def validate(self):
+ self.validate_interviewer()
+ self.validate_interview_date()
+ self.validate_duplicate()
+ self.calculate_average_rating()
+
+ def on_submit(self):
+ self.update_interview_details()
+
+ def on_cancel(self):
+ self.update_interview_details()
+
+ def validate_interviewer(self):
+ applicable_interviewers = get_applicable_interviewers(self.interview)
+ if self.interviewer not in applicable_interviewers:
+ frappe.throw(_('{0} is not allowed to submit Interview Feedback for the Interview: {1}').format(
+ frappe.bold(self.interviewer), frappe.bold(self.interview)))
+
+ def validate_interview_date(self):
+ scheduled_date = frappe.db.get_value('Interview', self.interview, 'scheduled_on')
+
+ if getdate() < getdate(scheduled_date) and self.docstatus == 1:
+ frappe.throw(_('{0} submission before {1} is not allowed').format(
+ frappe.bold('Interview Feedback'),
+ frappe.bold('Interview Scheduled Date')
+ ))
+
+ def validate_duplicate(self):
+ duplicate_feedback = frappe.db.exists('Interview Feedback', {
+ 'interviewer': self.interviewer,
+ 'interview': self.interview,
+ 'docstatus': 1
+ })
+
+ if duplicate_feedback:
+ frappe.throw(_('Feedback already submitted for the Interview {0}. Please cancel the previous Interview Feedback {1} to continue.').format(
+ self.interview, get_link_to_form('Interview Feedback', duplicate_feedback)))
+
+ def calculate_average_rating(self):
+ total_rating = 0
+ for d in self.skill_assessment:
+ if d.rating:
+ total_rating += d.rating
+
+ self.average_rating = flt(total_rating / len(self.skill_assessment) if len(self.skill_assessment) else 0)
+
+ def update_interview_details(self):
+ doc = frappe.get_doc('Interview', self.interview)
+ total_rating = 0
+
+ if self.docstatus == 2:
+ for entry in doc.interview_details:
+ if entry.interview_feedback == self.name:
+ entry.average_rating = entry.interview_feedback = entry.comments = entry.result = None
+ break
+ else:
+ for entry in doc.interview_details:
+ if entry.interviewer == self.interviewer:
+ entry.average_rating = self.average_rating
+ entry.interview_feedback = self.name
+ entry.comments = self.feedback
+ entry.result = self.result
+
+ if entry.average_rating:
+ total_rating += entry.average_rating
+
+ doc.average_rating = flt(total_rating / len(doc.interview_details) if len(doc.interview_details) else 0)
+ doc.save()
+ doc.notify_update()
+
+
+@frappe.whitelist()
+def get_applicable_interviewers(interview):
+ data = frappe.get_all('Interview Detail', filters={'parent': interview}, fields=['interviewer'])
+ return [d.interviewer for d in data]
diff --git a/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py b/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py
new file mode 100644
index 00000000000..c4b7981833b
--- /dev/null
+++ b/erpnext/hr/doctype/interview_feedback/test_interview_feedback.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+import frappe
+from frappe.utils import add_days, flt, getdate
+
+from erpnext.hr.doctype.interview.test_interview import (
+ create_interview_and_dependencies,
+ create_skill_set,
+)
+from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant
+
+
+class TestInterviewFeedback(unittest.TestCase):
+ def test_validation_for_skill_set(self):
+ frappe.set_user("Administrator")
+ job_applicant = create_job_applicant()
+ interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -1))
+ skill_ratings = get_skills_rating(interview.interview_round)
+
+ interviewer = interview.interview_details[0].interviewer
+ create_skill_set(['Leadership'])
+
+ interview_feedback = create_interview_feedback(interview.name, interviewer, skill_ratings)
+ interview_feedback.append("skill_assessment", {"skill": 'Leadership', 'rating': 4})
+ frappe.set_user(interviewer)
+
+ self.assertRaises(frappe.ValidationError, interview_feedback.save)
+
+ frappe.set_user("Administrator")
+
+ def test_average_ratings_on_feedback_submission_and_cancellation(self):
+ job_applicant = create_job_applicant()
+ interview = create_interview_and_dependencies(job_applicant.name, scheduled_on=add_days(getdate(), -1))
+ skill_ratings = get_skills_rating(interview.interview_round)
+
+ # For First Interviewer Feedback
+ interviewer = interview.interview_details[0].interviewer
+ frappe.set_user(interviewer)
+
+ # calculating Average
+ feedback_1 = create_interview_feedback(interview.name, interviewer, skill_ratings)
+
+ total_rating = 0
+ for d in feedback_1.skill_assessment:
+ if d.rating:
+ total_rating += d.rating
+
+ avg_rating = flt(total_rating / len(feedback_1.skill_assessment) if len(feedback_1.skill_assessment) else 0)
+
+ self.assertEqual(flt(avg_rating, 3), feedback_1.average_rating)
+
+ avg_on_interview_detail = frappe.db.get_value('Interview Detail', {
+ 'parent': feedback_1.interview,
+ 'interviewer': feedback_1.interviewer,
+ 'interview_feedback': feedback_1.name
+ }, 'average_rating')
+
+ # 1. average should be reflected in Interview Detail.
+ self.assertEqual(avg_on_interview_detail, round(feedback_1.average_rating))
+
+ '''For Second Interviewer Feedback'''
+ interviewer = interview.interview_details[1].interviewer
+ frappe.set_user(interviewer)
+
+ feedback_2 = create_interview_feedback(interview.name, interviewer, skill_ratings)
+ interview.reload()
+
+ feedback_2.cancel()
+ interview.reload()
+
+ frappe.set_user("Administrator")
+
+ def tearDown(self):
+ frappe.db.rollback()
+
+
+def create_interview_feedback(interview, interviewer, skills_ratings):
+ interview_feedback = frappe.new_doc("Interview Feedback")
+ interview_feedback.interview = interview
+ interview_feedback.interviewer = interviewer
+ interview_feedback.result = "Cleared"
+
+ for rating in skills_ratings:
+ interview_feedback.append("skill_assessment", rating)
+
+ interview_feedback.save()
+ interview_feedback.submit()
+
+ return interview_feedback
+
+
+def get_skills_rating(interview_round):
+ import random
+
+ skills = frappe.get_all("Expected Skill Set", filters={"parent": interview_round}, fields = ["skill"])
+ for d in skills:
+ d["rating"] = random.randint(1, 5)
+ return skills
diff --git a/erpnext/healthcare/doctype/codification_table/__init__.py b/erpnext/hr/doctype/interview_round/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/codification_table/__init__.py
rename to erpnext/hr/doctype/interview_round/__init__.py
diff --git a/erpnext/hr/doctype/interview_round/interview_round.js b/erpnext/hr/doctype/interview_round/interview_round.js
new file mode 100644
index 00000000000..6a608b03d25
--- /dev/null
+++ b/erpnext/hr/doctype/interview_round/interview_round.js
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Interview Round", {
+ refresh: function(frm) {
+ if (!frm.doc.__islocal) {
+ frm.add_custom_button(__("Create Interview"), function() {
+ frm.events.create_interview(frm);
+ });
+ }
+ },
+ create_interview: function(frm) {
+ frappe.call({
+ method: "erpnext.hr.doctype.interview_round.interview_round.create_interview",
+ args: {
+ doc: frm.doc
+ },
+ callback: function (r) {
+ var doclist = frappe.model.sync(r.message);
+ frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+ }
+ });
+ }
+});
diff --git a/erpnext/hr/doctype/interview_round/interview_round.json b/erpnext/hr/doctype/interview_round/interview_round.json
new file mode 100644
index 00000000000..9c95185e9ce
--- /dev/null
+++ b/erpnext/hr/doctype/interview_round/interview_round.json
@@ -0,0 +1,118 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "field:round_name",
+ "creation": "2021-04-12 12:57:19.902866",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "round_name",
+ "interview_type",
+ "interviewers",
+ "column_break_3",
+ "designation",
+ "expected_average_rating",
+ "expected_skills_section",
+ "expected_skill_set"
+ ],
+ "fields": [
+ {
+ "fieldname": "round_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Round Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "designation",
+ "fieldtype": "Link",
+ "label": "Designation",
+ "options": "Designation"
+ },
+ {
+ "fieldname": "expected_skills_section",
+ "fieldtype": "Section Break",
+ "label": "Expected Skillset"
+ },
+ {
+ "fieldname": "expected_skill_set",
+ "fieldtype": "Table",
+ "options": "Expected Skill Set",
+ "reqd": 1
+ },
+ {
+ "fieldname": "expected_average_rating",
+ "fieldtype": "Rating",
+ "label": "Expected Average Rating",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "interview_type",
+ "fieldtype": "Link",
+ "label": "Interview Type",
+ "options": "Interview Type",
+ "reqd": 1
+ },
+ {
+ "fieldname": "interviewers",
+ "fieldtype": "Table MultiSelect",
+ "label": "Interviewers",
+ "options": "Interviewer"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-09-30 13:01:25.666660",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Interview Round",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Interviewer",
+ "select": 1,
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/interview_round/interview_round.py b/erpnext/hr/doctype/interview_round/interview_round.py
new file mode 100644
index 00000000000..8230c785852
--- /dev/null
+++ b/erpnext/hr/doctype/interview_round/interview_round.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import json
+
+import frappe
+from frappe.model.document import Document
+
+
+class InterviewRound(Document):
+ pass
+
+@frappe.whitelist()
+def create_interview(doc):
+ if isinstance(doc, str):
+ doc = json.loads(doc)
+ doc = frappe.get_doc(doc)
+
+ interview = frappe.new_doc("Interview")
+ interview.interview_round = doc.name
+ interview.designation = doc.designation
+
+ if doc.interviewers:
+ interview.interview_details = []
+ for data in doc.interviewers:
+ interview.append("interview_details", {
+ "interviewer": data.user
+ })
+ return interview
+
+
+
diff --git a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py b/erpnext/hr/doctype/interview_round/test_interview_round.py
similarity index 53%
rename from erpnext/healthcare/doctype/therapy_session/test_therapy_session.py
rename to erpnext/hr/doctype/interview_round/test_interview_round.py
index e4afacf3f0a..932d3defc2c 100644
--- a/erpnext/healthcare/doctype/therapy_session/test_therapy_session.py
+++ b/erpnext/hr/doctype/interview_round/test_interview_round.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
-# import frappe
import unittest
+# import frappe
-class TestTherapySession(unittest.TestCase):
+
+class TestInterviewRound(unittest.TestCase):
pass
+
diff --git a/erpnext/healthcare/doctype/complaint/__init__.py b/erpnext/hr/doctype/interview_type/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/complaint/__init__.py
rename to erpnext/hr/doctype/interview_type/__init__.py
diff --git a/erpnext/hr/doctype/interview_type/interview_type.js b/erpnext/hr/doctype/interview_type/interview_type.js
new file mode 100644
index 00000000000..af77b527d4d
--- /dev/null
+++ b/erpnext/hr/doctype/interview_type/interview_type.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Interview Type', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json b/erpnext/hr/doctype/interview_type/interview_type.json
similarity index 61%
rename from erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
rename to erpnext/hr/doctype/interview_type/interview_type.json
index 1971458f61e..14636a18cb3 100644
--- a/erpnext/buying/doctype/supplier_item_group/supplier_item_group.json
+++ b/erpnext/hr/doctype/interview_type/interview_type.json
@@ -1,37 +1,33 @@
{
"actions": [],
- "creation": "2021-05-07 18:16:40.621421",
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2021-04-12 14:44:40.664034",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "supplier",
- "item_group"
+ "description"
],
"fields": [
{
- "fieldname": "supplier",
- "fieldtype": "Link",
+ "fieldname": "description",
+ "fieldtype": "Text",
"in_list_view": 1,
- "label": "Supplier",
- "options": "Supplier",
- "reqd": 1
- },
- {
- "fieldname": "item_group",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item Group",
- "options": "Item Group",
- "reqd": 1
+ "label": "Description"
}
],
"index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-05-19 13:48:16.742303",
+ "links": [
+ {
+ "link_doctype": "Interview Round",
+ "link_fieldname": "interview_type"
+ }
+ ],
+ "modified": "2021-09-30 13:00:16.471518",
"modified_by": "Administrator",
- "module": "Buying",
- "name": "Supplier Item Group",
+ "module": "HR",
+ "name": "Interview Type",
"owner": "Administrator",
"permissions": [
{
@@ -54,7 +50,7 @@
"print": 1,
"read": 1,
"report": 1,
- "role": "Purchase User",
+ "role": "HR Manager",
"share": 1,
"write": 1
},
@@ -66,7 +62,7 @@
"print": 1,
"read": 1,
"report": 1,
- "role": "Purchase Manager",
+ "role": "HR User",
"share": 1,
"write": 1
}
diff --git a/erpnext/healthcare/doctype/body_part/body_part.py b/erpnext/hr/doctype/interview_type/interview_type.py
similarity index 66%
rename from erpnext/healthcare/doctype/body_part/body_part.py
rename to erpnext/hr/doctype/interview_type/interview_type.py
index 77e8dd90a07..ee5be54c755 100644
--- a/erpnext/healthcare/doctype/body_part/body_part.py
+++ b/erpnext/hr/doctype/interview_type/interview_type.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
@@ -8,5 +8,5 @@ from __future__ import unicode_literals
from frappe.model.document import Document
-class BodyPart(Document):
+class InterviewType(Document):
pass
diff --git a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py b/erpnext/hr/doctype/interview_type/test_interview_type.py
similarity index 54%
rename from erpnext/healthcare/doctype/exercise_type/test_exercise_type.py
rename to erpnext/hr/doctype/interview_type/test_interview_type.py
index 583aea911ae..a5d3cf99229 100644
--- a/erpnext/healthcare/doctype/exercise_type/test_exercise_type.py
+++ b/erpnext/hr/doctype/interview_type/test_interview_type.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
@@ -7,5 +7,5 @@ from __future__ import unicode_literals
import unittest
-class TestExerciseType(unittest.TestCase):
+class TestInterviewType(unittest.TestCase):
pass
diff --git a/erpnext/healthcare/doctype/descriptive_test_result/__init__.py b/erpnext/hr/doctype/interviewer/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/descriptive_test_result/__init__.py
rename to erpnext/hr/doctype/interviewer/__init__.py
diff --git a/erpnext/healthcare/doctype/body_part_link/body_part_link.json b/erpnext/hr/doctype/interviewer/interviewer.json
similarity index 57%
rename from erpnext/healthcare/doctype/body_part_link/body_part_link.json
rename to erpnext/hr/doctype/interviewer/interviewer.json
index 400b7c6fe81..a37b8b0e4e5 100644
--- a/erpnext/healthcare/doctype/body_part_link/body_part_link.json
+++ b/erpnext/hr/doctype/interviewer/interviewer.json
@@ -1,31 +1,30 @@
{
"actions": [],
- "creation": "2020-04-10 12:23:15.259816",
+ "creation": "2021-04-12 17:38:19.354734",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "body_part"
+ "user"
],
"fields": [
{
- "fieldname": "body_part",
+ "fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Body Part",
- "options": "Body Part",
- "reqd": 1
+ "label": "User",
+ "options": "User"
}
],
+ "index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-10 12:25:23.101749",
+ "modified": "2021-04-13 13:41:35.817568",
"modified_by": "Administrator",
- "module": "Healthcare",
- "name": "Body Part Link",
+ "module": "HR",
+ "name": "Interviewer",
"owner": "Administrator",
"permissions": [],
- "quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
diff --git a/erpnext/healthcare/doctype/exercise/exercise.py b/erpnext/hr/doctype/interviewer/interviewer.py
similarity index 66%
rename from erpnext/healthcare/doctype/exercise/exercise.py
rename to erpnext/hr/doctype/interviewer/interviewer.py
index 5d2b1f1a96d..1c8dbbed591 100644
--- a/erpnext/healthcare/doctype/exercise/exercise.py
+++ b/erpnext/hr/doctype/interviewer/interviewer.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
@@ -8,5 +8,5 @@ from __future__ import unicode_literals
from frappe.model.document import Document
-class Exercise(Document):
+class Interviewer(Document):
pass
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.js b/erpnext/hr/doctype/job_applicant/job_applicant.js
index 7658bc93539..d7b1c6c9df3 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.js
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.js
@@ -8,6 +8,24 @@ cur_frm.email_field = "email_id";
frappe.ui.form.on("Job Applicant", {
refresh: function(frm) {
+ frm.set_query("job_title", function() {
+ return {
+ filters: {
+ 'status': 'Open'
+ }
+ };
+ });
+ frm.events.create_custom_buttons(frm);
+ frm.events.make_dashboard(frm);
+ },
+
+ create_custom_buttons: function(frm) {
+ if (!frm.doc.__islocal && frm.doc.status !== "Rejected" && frm.doc.status !== "Accepted") {
+ frm.add_custom_button(__("Create Interview"), function() {
+ frm.events.create_dialog(frm);
+ });
+ }
+
if (!frm.doc.__islocal) {
if (frm.doc.__onload && frm.doc.__onload.job_offer) {
$('[data-doctype="Employee Onboarding"]').find("button").show();
@@ -28,14 +46,57 @@ frappe.ui.form.on("Job Applicant", {
});
}
}
+ },
- frm.set_query("job_title", function() {
- return {
- filters: {
- 'status': 'Open'
- }
- };
+ make_dashboard: function(frm) {
+ frappe.call({
+ method: "erpnext.hr.doctype.job_applicant.job_applicant.get_interview_details",
+ args: {
+ job_applicant: frm.doc.name
+ },
+ callback: function(r) {
+ $("div").remove(".form-dashboard-section.custom");
+ frm.dashboard.add_section(
+ frappe.render_template('job_applicant_dashboard', {
+ data: r.message
+ }),
+ __("Interview Summary")
+ );
+ }
});
+ },
+ create_dialog: function(frm) {
+ let d = new frappe.ui.Dialog({
+ title: 'Enter Interview Round',
+ fields: [
+ {
+ label: 'Interview Round',
+ fieldname: 'interview_round',
+ fieldtype: 'Link',
+ options: 'Interview Round'
+ },
+ ],
+ primary_action_label: 'Create Interview',
+ primary_action(values) {
+ frm.events.create_interview(frm, values);
+ d.hide();
+ }
+ });
+ d.show();
+ },
+
+ create_interview: function (frm, values) {
+ frappe.call({
+ method: "erpnext.hr.doctype.job_applicant.job_applicant.create_interview",
+ args: {
+ doc: frm.doc,
+ interview_round: values.interview_round
+ },
+ callback: function (r) {
+ var doclist = frappe.model.sync(r.message);
+ frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+ }
+ });
}
});
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json
index bcea5f50d93..200f675221b 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.json
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.json
@@ -9,16 +9,20 @@
"email_append_to": 1,
"engine": "InnoDB",
"field_order": [
+ "details_section",
"applicant_name",
"email_id",
"phone_number",
"country",
- "status",
"column_break_3",
"job_title",
+ "designation",
+ "status",
+ "source_and_rating_section",
"source",
"source_name",
"employee_referral",
+ "column_break_13",
"applicant_rating",
"section_break_6",
"notes",
@@ -84,7 +88,8 @@
},
{
"fieldname": "section_break_6",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Resume"
},
{
"fieldname": "cover_letter",
@@ -160,13 +165,34 @@
"label": "Employee Referral",
"options": "Employee Referral",
"read_only": 1
+ },
+ {
+ "fieldname": "details_section",
+ "fieldtype": "Section Break",
+ "label": "Details"
+ },
+ {
+ "fieldname": "source_and_rating_section",
+ "fieldtype": "Section Break",
+ "label": "Source and Rating"
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "job_opening.designation",
+ "fieldname": "designation",
+ "fieldtype": "Link",
+ "label": "Designation",
+ "options": "Designation"
}
],
"icon": "fa fa-user",
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2021-03-24 15:51:11.117517",
+ "modified": "2021-09-29 23:06:10.904260",
"modified_by": "Administrator",
"module": "HR",
"name": "Job Applicant",
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index 6971e5b4fef..151f49248fd 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -8,7 +8,9 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import comma_and, validate_email_address
+from frappe.utils import validate_email_address
+
+from erpnext.hr.doctype.interview.interview import get_interviewers
class DuplicationError(frappe.ValidationError): pass
@@ -26,7 +28,6 @@ class JobApplicant(Document):
self.name = " - ".join(keys)
def validate(self):
- self.check_email_id_is_unique()
if self.email_id:
validate_email_address(self.email_id, True)
@@ -44,11 +45,44 @@ class JobApplicant(Document):
elif self.status in ["Accepted", "Rejected"]:
emp_ref.db_set("status", self.status)
+@frappe.whitelist()
+def create_interview(doc, interview_round):
+ import json
- def check_email_id_is_unique(self):
- if self.email_id:
- names = frappe.db.sql_list("""select name from `tabJob Applicant`
- where email_id=%s and name!=%s and job_title=%s""", (self.email_id, self.name, self.job_title))
+ from six import string_types
- if names:
- frappe.throw(_("Email Address must be unique, already exists for {0}").format(comma_and(names)), frappe.DuplicateEntryError)
+ if isinstance(doc, string_types):
+ doc = json.loads(doc)
+ doc = frappe.get_doc(doc)
+
+ round_designation = frappe.db.get_value("Interview Round", interview_round, "designation")
+
+ if round_designation and doc.designation and round_designation != doc.designation:
+ frappe.throw(_("Interview Round {0} is only applicable for the Designation {1}").format(interview_round, round_designation))
+
+ interview = frappe.new_doc("Interview")
+ interview.interview_round = interview_round
+ interview.job_applicant = doc.name
+ interview.designation = doc.designation
+ interview.resume_link = doc.resume_link
+ interview.job_opening = doc.job_title
+ interviewer_detail = get_interviewers(interview_round)
+
+ for d in interviewer_detail:
+ interview.append("interview_details", {
+ "interviewer": d.interviewer
+ })
+ return interview
+
+@frappe.whitelist()
+def get_interview_details(job_applicant):
+ interview_details = frappe.db.get_all("Interview",
+ filters={"job_applicant":job_applicant, "docstatus": ["!=", 2]},
+ fields=["name", "interview_round", "expected_average_rating", "average_rating", "status"]
+ )
+ interview_detail_map = {}
+
+ for detail in interview_details:
+ interview_detail_map[detail.name] = detail
+
+ return interview_detail_map
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html
new file mode 100644
index 00000000000..c286787a556
--- /dev/null
+++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.html
@@ -0,0 +1,44 @@
+
+{% if not jQuery.isEmptyObject(data) %}
+
+ No Interview has been scheduled.
+{% endif %}
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
index c0059431cfc..2f7795fc089 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant_dashboard.py
@@ -2,14 +2,17 @@ from __future__ import unicode_literals
def get_data():
- return {
- 'fieldname': 'job_applicant',
- 'transactions': [
- {
- 'items': ['Employee', 'Employee Onboarding']
- },
- {
- 'items': ['Job Offer']
- },
- ],
- }
+ return {
+ 'fieldname': 'job_applicant',
+ 'transactions': [
+ {
+ 'items': ['Employee', 'Employee Onboarding']
+ },
+ {
+ 'items': ['Job Offer', 'Appointment Letter']
+ },
+ {
+ 'items': ['Interview']
+ }
+ ],
+ }
diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.py b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
index e583e25eae0..8fc12907421 100644
--- a/erpnext/hr/doctype/job_applicant/test_job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
@@ -7,7 +7,8 @@ import unittest
import frappe
-# test_records = frappe.get_test_records('Job Applicant')
+from erpnext.hr.doctype.designation.test_designation import create_designation
+
class TestJobApplicant(unittest.TestCase):
pass
@@ -25,7 +26,8 @@ def create_job_applicant(**args):
job_applicant = frappe.get_doc({
"doctype": "Job Applicant",
- "status": args.status or "Open"
+ "status": args.status or "Open",
+ "designation": create_designation().name
})
job_applicant.update(filters)
diff --git a/erpnext/hr/doctype/job_offer/test_job_offer.py b/erpnext/hr/doctype/job_offer/test_job_offer.py
index 3f3eca17e62..162b245d13c 100644
--- a/erpnext/hr/doctype/job_offer/test_job_offer.py
+++ b/erpnext/hr/doctype/job_offer/test_job_offer.py
@@ -32,6 +32,7 @@ class TestJobOffer(unittest.TestCase):
self.assertTrue(frappe.db.exists("Job Offer", job_offer.name))
def test_job_applicant_update(self):
+ frappe.db.set_value("HR Settings", None, "check_vacancies", 0)
create_staffing_plan()
job_applicant = create_job_applicant(email_id="test_job_applicants@example.com")
job_offer = create_job_offer(job_applicant=job_applicant.name)
@@ -43,7 +44,11 @@ class TestJobOffer(unittest.TestCase):
job_offer.status = "Rejected"
job_offer.submit()
job_applicant.reload()
- self.assertEqual(job_applicant.status, "Rejected")
+ self.assertEquals(job_applicant.status, "Rejected")
+ frappe.db.set_value("HR Settings", None, "check_vacancies", 1)
+
+ def tearDown(self):
+ frappe.db.sql("DELETE FROM `tabJob Offer` WHERE 1")
def create_job_offer(**args):
args = frappe._dict(args)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index d94764104d0..9742387c16a 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -1,14 +1,14 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-cur_frm.add_fetch('employee','employee_name','employee_name');
+cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
frappe.ui.form.on("Leave Allocation", {
onload: function(frm) {
// Ignore cancellation of doctype on cancel all.
frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"];
- if(!frm.doc.from_date) frm.set_value("from_date", frappe.datetime.get_today());
+ if (!frm.doc.from_date) frm.set_value("from_date", frappe.datetime.get_today());
frm.set_query("employee", function() {
return {
@@ -25,9 +25,9 @@ frappe.ui.form.on("Leave Allocation", {
},
refresh: function(frm) {
- if(frm.doc.docstatus === 1 && frm.doc.expired) {
+ if (frm.doc.docstatus === 1 && frm.doc.expired) {
var valid_expiry = moment(frappe.datetime.get_today()).isBetween(frm.doc.from_date, frm.doc.to_date);
- if(valid_expiry) {
+ if (valid_expiry) {
// expire current allocation
frm.add_custom_button(__('Expire Allocation'), function() {
frm.trigger("expire_allocation");
@@ -44,8 +44,8 @@ frappe.ui.form.on("Leave Allocation", {
'expiry_date': frappe.datetime.get_today()
},
freeze: true,
- callback: function(r){
- if(!r.exc){
+ callback: function(r) {
+ if (!r.exc) {
frappe.msgprint(__("Allocation Expired!"));
}
frm.refresh();
@@ -77,8 +77,8 @@ frappe.ui.form.on("Leave Allocation", {
},
leave_policy: function(frm) {
- if(frm.doc.leave_policy && frm.doc.leave_type) {
- frappe.db.get_value("Leave Policy Detail",{
+ if (frm.doc.leave_policy && frm.doc.leave_type) {
+ frappe.db.get_value("Leave Policy Detail", {
'parent': frm.doc.leave_policy,
'leave_type': frm.doc.leave_type
}, 'annual_allocation', (r) => {
@@ -91,13 +91,41 @@ frappe.ui.form.on("Leave Allocation", {
return frappe.call({
method: "set_total_leaves_allocated",
doc: frm.doc,
- callback: function(r) {
+ callback: function() {
frm.refresh_fields();
}
- })
+ });
} else if (cint(frm.doc.carry_forward) == 0) {
frm.set_value("unused_leaves", 0);
frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
}
}
});
+
+frappe.tour["Leave Allocation"] = [
+ {
+ fieldname: "employee",
+ title: "Employee",
+ description: __("Select the Employee for which you want to allocate leaves.")
+ },
+ {
+ fieldname: "leave_type",
+ title: "Leave Type",
+ description: __("Select the Leave Type like Sick leave, Privilege Leave, Casual Leave, etc.")
+ },
+ {
+ fieldname: "from_date",
+ title: "From Date",
+ description: __("Select the date from which this Leave Allocation will be valid.")
+ },
+ {
+ fieldname: "to_date",
+ title: "To Date",
+ description: __("Select the date after which this Leave Allocation will expire.")
+ },
+ {
+ fieldname: "new_leaves_allocated",
+ title: "New Leaves Allocated",
+ description: __("Enter the number of leaves you want to allocate for the period.")
+ }
+];
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 3a6539ece9e..52ee463db02 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -219,7 +219,8 @@
"fieldname": "leave_policy_assignment",
"fieldtype": "Link",
"label": "Leave Policy Assignment",
- "options": "Leave Policy Assignment"
+ "options": "Leave Policy Assignment",
+ "read_only": 1
},
{
"fetch_from": "employee.company",
@@ -236,7 +237,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2021-06-03 15:28:26.335104",
+ "modified": "2021-10-01 15:28:26.335104",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Allocation",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 9ccb915908f..9e8cb5516f3 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -1,8 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-cur_frm.add_fetch('employee','employee_name','employee_name');
-cur_frm.add_fetch('employee','company','company');
+cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
+cur_frm.add_fetch('employee', 'company', 'company');
frappe.ui.form.on("Leave Application", {
setup: function(frm) {
@@ -19,7 +19,6 @@ frappe.ui.form.on("Leave Application", {
frm.set_query("employee", erpnext.queries.employee);
},
onload: function(frm) {
-
// Ignore cancellation of doctype on cancel all.
frm.ignore_doctypes_on_cancel_all = ["Leave Ledger Entry"];
@@ -42,9 +41,9 @@ frappe.ui.form.on("Leave Application", {
},
validate: function(frm) {
- if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1){
+ if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1) {
frm.doc.half_day_date = frm.doc.from_date;
- }else if (frm.doc.half_day == 0){
+ } else if (frm.doc.half_day == 0) {
frm.doc.half_day_date = "";
}
frm.toggle_reqd("half_day_date", frm.doc.half_day == 1);
@@ -79,14 +78,14 @@ frappe.ui.form.on("Leave Application", {
__("Allocated Leaves")
);
frm.dashboard.show();
- let allowed_leave_types = Object.keys(leave_details);
+ let allowed_leave_types = Object.keys(leave_details);
// lwps should be allowed, lwps don't have any allocation
allowed_leave_types = allowed_leave_types.concat(lwps);
- frm.set_query('leave_type', function(){
+ frm.set_query('leave_type', function() {
return {
- filters : [
+ filters: [
['leave_type_name', 'in', allowed_leave_types]
]
};
@@ -99,7 +98,7 @@ frappe.ui.form.on("Leave Application", {
frm.trigger("calculate_total_days");
}
cur_frm.set_intro("");
- if(frm.doc.__islocal && !in_list(frappe.user_roles, "Employee")) {
+ if (frm.doc.__islocal && !in_list(frappe.user_roles, "Employee")) {
frm.set_intro(__("Fill the form and save it"));
}
@@ -118,7 +117,7 @@ frappe.ui.form.on("Leave Application", {
},
leave_approver: function(frm) {
- if(frm.doc.leave_approver){
+ if (frm.doc.leave_approver) {
frm.set_value("leave_approver_name", frappe.user.full_name(frm.doc.leave_approver));
}
},
@@ -131,12 +130,10 @@ frappe.ui.form.on("Leave Application", {
if (frm.doc.half_day) {
if (frm.doc.from_date == frm.doc.to_date) {
frm.set_value("half_day_date", frm.doc.from_date);
- }
- else {
+ } else {
frm.trigger("half_day_datepicker");
}
- }
- else {
+ } else {
frm.set_value("half_day_date", "");
}
frm.trigger("calculate_total_days");
@@ -163,11 +160,11 @@ frappe.ui.form.on("Leave Application", {
half_day_datepicker.update({
minDate: frappe.datetime.str_to_obj(frm.doc.from_date),
maxDate: frappe.datetime.str_to_obj(frm.doc.to_date)
- })
+ });
},
get_leave_balance: function(frm) {
- if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) {
+ if (frm.doc.docstatus === 0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) {
return frappe.call({
method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on",
args: {
@@ -177,11 +174,10 @@ frappe.ui.form.on("Leave Application", {
leave_type: frm.doc.leave_type,
consider_all_leaves_in_the_allocation_period: true
},
- callback: function(r) {
+ callback: function (r) {
if (!r.exc && r.message) {
frm.set_value('leave_balance', r.message);
- }
- else {
+ } else {
frm.set_value('leave_balance', "0");
}
}
@@ -190,12 +186,12 @@ frappe.ui.form.on("Leave Application", {
},
calculate_total_days: function(frm) {
- if(frm.doc.from_date && frm.doc.to_date && frm.doc.employee && frm.doc.leave_type) {
+ if (frm.doc.from_date && frm.doc.to_date && frm.doc.employee && frm.doc.leave_type) {
var from_date = Date.parse(frm.doc.from_date);
var to_date = Date.parse(frm.doc.to_date);
- if(to_date < from_date){
+ if (to_date < from_date) {
frappe.msgprint(__("To Date cannot be less than From Date"));
frm.set_value('to_date', '');
return;
@@ -222,7 +218,7 @@ frappe.ui.form.on("Leave Application", {
},
set_leave_approver: function(frm) {
- if(frm.doc.employee) {
+ if (frm.doc.employee) {
// server call is done to include holidays in leave days calculations
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver',
@@ -238,3 +234,36 @@ frappe.ui.form.on("Leave Application", {
}
}
});
+
+frappe.tour["Leave Application"] = [
+ {
+ fieldname: "employee",
+ title: "Employee",
+ description: __("Select the Employee.")
+ },
+ {
+ fieldname: "leave_type",
+ title: "Leave Type",
+ description: __("Select type of leave the employee wants to apply for, like Sick Leave, Privilege Leave, Casual Leave, etc.")
+ },
+ {
+ fieldname: "from_date",
+ title: "From Date",
+ description: __("Select the start date for your Leave Application.")
+ },
+ {
+ fieldname: "to_date",
+ title: "To Date",
+ description: __("Select the end date for your Leave Application.")
+ },
+ {
+ fieldname: "half_day",
+ title: "Half Day",
+ description: __("To apply for a Half Day check 'Half Day' and select the Half Day Date")
+ },
+ {
+ fieldname: "leave_approver",
+ title: "Leave Approver",
+ description: __("Select your Leave Approver i.e. the person who approves or rejects your leaves.")
+ }
+];
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 9e6fc6d0f14..349ed7ad227 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -76,6 +76,7 @@ class LeaveApplication(Document):
# notify leave applier about approval
if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
self.notify_employee()
+
self.create_leave_ledger_entry()
self.reload()
@@ -108,7 +109,13 @@ class LeaveApplication(Document):
if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"):
if self.from_date and getdate(self.from_date) < getdate():
allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application")
- if allowed_role not in frappe.get_roles():
+ user = frappe.get_doc("User", frappe.session.user)
+ user_roles = [d.role for d in user.roles]
+ if not allowed_role:
+ frappe.throw(_("Backdated Leave Application is restricted. Please set the {} in {}").format(
+ frappe.bold("Role Allowed to Create Backdated Leave Application"), get_link_to_form("HR Settings", "HR Settings")))
+
+ if (allowed_role and allowed_role not in user_roles):
frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role))
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index b9c785a8a9c..629b20e768e 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -121,6 +121,7 @@ class TestLeaveApplication(unittest.TestCase):
application = self.get_application(_test_records[0])
application.insert()
+ application.reload()
application.status = "Approved"
self.assertRaises(LeaveDayBlockedError, application.submit)
diff --git a/erpnext/hr/doctype/leave_type/leave_type.js b/erpnext/hr/doctype/leave_type/leave_type.js
index 8622309848a..b930dedaca8 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.js
+++ b/erpnext/hr/doctype/leave_type/leave_type.js
@@ -2,3 +2,37 @@ frappe.ui.form.on("Leave Type", {
refresh: function(frm) {
}
});
+
+
+frappe.tour["Leave Type"] = [
+ {
+ fieldname: "max_leaves_allowed",
+ title: "Maximum Leave Allocation Allowed",
+ description: __("This field allows you to set the maximum number of leaves that can be allocated annually for this Leave Type while creating the Leave Policy")
+ },
+ {
+ fieldname: "max_continuous_days_allowed",
+ title: "Maximum Consecutive Leaves Allowed",
+ description: __("This field allows you to set the maximum number of consecutive leaves an Employee can apply for.")
+ },
+ {
+ fieldname: "is_optional_leave",
+ title: "Is Optional Leave",
+ description: __("Optional Leaves are holidays that Employees can choose to avail from a list of holidays published by the company.")
+ },
+ {
+ fieldname: "is_compensatory",
+ title: "Is Compensatory Leave",
+ description: __("Leaves you can avail against a holiday you worked on. You can claim Compensatory Off Leave using Compensatory Leave request. Click") + " ').appendTo(this.$sidebar)[0],
- render: h => h(Sidebar)
- });
- }
-
- make_body() {
- this.$body = this.$parent.find('.layout-main-section');
- this.$page_container = $('
').appendTo(this.$body);
-
- new Vue({
- el: '.hub-page-container',
- render: h => h(PageContainer)
- });
-
- if (!hub.is_server) {
- erpnext.hub.on('seller-registered', () => {
- this.page.clear_primary_action();
- });
- }
- }
-
- refresh() {
-
- }
-
- show_register_dialog() {
- if(frappe.session.user === 'Administrator') {
- frappe.msgprint(__('You need to be a user other than Administrator with System Manager and Item Manager roles to register on Marketplace.'));
- return;
- }
-
- if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) {
- frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to register on Marketplace.'));
- return;
- }
-
- this.register_dialog = ProfileDialog(
- __('Become a Seller'),
- {
- label: __('Register'),
- on_submit: this.register_marketplace.bind(this)
- }
- );
-
- this.register_dialog.show();
- }
-
- register_marketplace({company, company_description}) {
- frappe.call({
- method: 'erpnext.hub_node.api.register_marketplace',
- args: {
- company,
- company_description
- }
- }).then((r) => {
- if (r.message && r.message.ok) {
- this.register_dialog.hide();
-
- this.update_hub_settings()
- .then(() => {
- frappe.set_route('marketplace', 'publish');
- erpnext.hub.trigger('seller-registered');
- });
- }
- });
- }
-
- show_add_user_dialog() {
- if (!is_subset(['System Manager', 'Item Manager'], frappe.user_roles)) {
- frappe.msgprint(__('You need to be a user with System Manager and Item Manager roles to add users to Marketplace.'));
- return;
- }
-
- this.get_unregistered_users()
- .then(r => {
- const user_list = r.message;
-
- const d = new frappe.ui.Dialog({
- title: __('Add Users to Marketplace'),
- fields: [
- {
- label: __('Users'),
- fieldname: 'users',
- fieldtype: 'MultiSelect',
- reqd: 1,
- get_data() {
- return user_list;
- }
- }
- ],
- primary_action({ users }) {
- const selected_users = users.split(',').map(d => d.trim()).filter(Boolean);
-
- if (!selected_users.every(user => user_list.includes(user))) {
- d.set_df_property('users', 'description', __('Some emails are invalid'));
- return;
- } else {
- d.set_df_property('users', 'description', '');
- }
-
- frappe.call('erpnext.hub_node.api.register_users', {
- user_list: selected_users
- })
- .then(r => {
- d.hide();
-
- if (r.message && r.message.length) {
- frappe.show_alert(__('Added {0} users', [r.message.length]));
- }
- });
- }
- });
-
- d.show();
- });
- }
-
- get_unregistered_users() {
- return frappe.call('erpnext.hub_node.api.get_unregistered_users')
- }
-
- update_hub_settings() {
- return hub.get_settings().then(doc => {
- hub.settings = doc;
- });
- }
-}
-
-Object.assign(hub, {
- is_seller_registered() {
- return hub.settings.registered;
- },
-
- is_user_registered() {
- return this.is_seller_registered() && hub.settings.users
- .filter(hub_user => hub_user.user === frappe.session.user)
- .length === 1;
- },
-
- get_settings() {
- if (frappe.session.user === 'Guest') {
- return Promise.resolve({
- registered: 0
- });
- }
- return frappe.db.get_doc('Marketplace Settings');
- }
-});
-
-/**
- * Returns true if list_a is subset of list_b
- * @param {Array} list_a
- * @param {Array} list_b
- */
-function is_subset(list_a, list_b) {
- return list_a.every(item => list_b.includes(item));
-}
diff --git a/erpnext/public/js/hub/pages/Buying.vue b/erpnext/public/js/hub/pages/Buying.vue
deleted file mode 100644
index ebf593aca4d..00000000000
--- a/erpnext/public/js/hub/pages/Buying.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
- {{ __('Buying') }}
-
-
-
-
-
- {{ get_sender(item.recent_message) }}:
- {{ item.recent_message.message | striphtml }}
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue
deleted file mode 100644
index 16d06018ff0..00000000000
--- a/erpnext/public/js/hub/pages/Category.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
{{ page_title }}
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/FeaturedItems.vue b/erpnext/public/js/hub/pages/FeaturedItems.vue
deleted file mode 100644
index 8380b2b2c0b..00000000000
--- a/erpnext/public/js/hub/pages/FeaturedItems.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
{{ page_title }}
-
- {{ __('You can Feature upto 8 items.') }}
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Home.vue b/erpnext/public/js/hub/pages/Home.vue
deleted file mode 100644
index 8fe824566db..00000000000
--- a/erpnext/public/js/hub/pages/Home.vue
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
- Explore Explore Explore
-
-
-
-
-
-
-
- {{ section.title }}
- {{ 'See All' }}
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
deleted file mode 100644
index 93002a7b27a..00000000000
--- a/erpnext/public/js/hub/pages/Item.vue
+++ /dev/null
@@ -1,356 +0,0 @@
-
-
-
-
-
-
- {{ primary_action.label }}
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Messages.vue b/erpnext/public/js/hub/pages/Messages.vue
deleted file mode 100644
index 73506e99266..00000000000
--- a/erpnext/public/js/hub/pages/Messages.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
-
{{ item_details.item_name }}
- {{ item_details.company }}
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/NotFound.vue b/erpnext/public/js/hub/pages/NotFound.vue
deleted file mode 100644
index 8901b97802d..00000000000
--- a/erpnext/public/js/hub/pages/NotFound.vue
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Publish.vue b/erpnext/public/js/hub/pages/Publish.vue
deleted file mode 100644
index ecba4b1e5a8..00000000000
--- a/erpnext/public/js/hub/pages/Publish.vue
+++ /dev/null
@@ -1,212 +0,0 @@
-
-
-
-
-
-
{{ page_title }}
-
-
- {{ publish_button_text }}
-
-
-
-
-
-
-
{{ valid_items_instruction }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/PublishedItems.vue b/erpnext/public/js/hub/pages/PublishedItems.vue
deleted file mode 100644
index cbb22164e6e..00000000000
--- a/erpnext/public/js/hub/pages/PublishedItems.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
{{ __('Published Items') }}
-
- {{ __('You can publish upto 200 items.') }}
-
-
-
-
- {{ __('Publish More Items') }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/SavedItems.vue b/erpnext/public/js/hub/pages/SavedItems.vue
deleted file mode 100644
index 7007ddcf8e7..00000000000
--- a/erpnext/public/js/hub/pages/SavedItems.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
{{ page_title }}
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue
deleted file mode 100644
index c10841e9848..00000000000
--- a/erpnext/public/js/hub/pages/Search.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
{{ page_title }}
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Seller.vue b/erpnext/public/js/hub/pages/Seller.vue
deleted file mode 100644
index 3c9b800f4a0..00000000000
--- a/erpnext/public/js/hub/pages/Seller.vue
+++ /dev/null
@@ -1,201 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Customer Reviews
-
-
-
-
-
-
-
{{ review.subject }}
-
-
- by {{ review.username }}
-
- –
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/SellerItems.vue b/erpnext/public/js/hub/pages/SellerItems.vue
deleted file mode 100644
index 852fbaee3ff..00000000000
--- a/erpnext/public/js/hub/pages/SellerItems.vue
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
{{ item_container_heading }}
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/pages/Selling.vue b/erpnext/public/js/hub/pages/Selling.vue
deleted file mode 100644
index 8743027885d..00000000000
--- a/erpnext/public/js/hub/pages/Selling.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
- {{ __('Selling') }}
-
-
-
-
-
- {{ __('{0} conversations', [item.received_messages.length]) }}
-
-
-
-
-
-
- {{ message.buyer_name }}
-
-
- {{ message.sender }}: {{ message.message | striphtml }}
-
-
-
-
-
-
-
-
-
-
diff --git a/erpnext/public/js/hub/vue-plugins.js b/erpnext/public/js/hub/vue-plugins.js
deleted file mode 100644
index 4912d684991..00000000000
--- a/erpnext/public/js/hub/vue-plugins.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import Vue from 'vue/dist/vue.js';
-
-// Global components
-import ItemCardsContainer from './components/ItemCardsContainer.vue';
-import SectionHeader from './components/SectionHeader.vue';
-import SearchInput from './components/SearchInput.vue';
-import DetailView from './components/DetailView.vue';
-import DetailHeaderItem from './components/DetailHeaderItem.vue';
-import EmptyState from './components/EmptyState.vue';
-import Image from './components/Image.vue';
-
-Vue.prototype.__ = window.__;
-Vue.prototype.frappe = window.frappe;
-
-Vue.component('item-cards-container', ItemCardsContainer);
-Vue.component('section-header', SectionHeader);
-Vue.component('search-input', SearchInput);
-Vue.component('detail-view', DetailView);
-Vue.component('detail-header-item', DetailHeaderItem);
-Vue.component('empty-state', EmptyState);
-Vue.component('base-image', Image);
-
-Vue.directive('route', {
- bind(el, binding) {
- const route = binding.value;
- if (!route) return;
- el.classList.add('cursor-pointer');
- el.dataset.route = route;
- el.addEventListener('click', () => frappe.set_route(route));
- },
- unbind(el) {
- el.classList.remove('cursor-pointer');
- }
-});
-
-const handleImage = (el, src) => {
- let img = new Image();
- // add loading class
- el.src = '';
- el.classList.add('img-loading');
-
- img.onload = () => {
- // image loaded, remove loading class
- el.classList.remove('img-loading');
- // set src
- el.src = src;
- }
- img.onerror = () => {
- el.classList.remove('img-loading');
- el.classList.add('no-image');
- el.src = null;
- }
- img.src = src;
-}
-
-Vue.filter('striphtml', function (text) {
- return strip_html(text || '');
-});
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index e0610eb8c01..0323a426f0e 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -709,14 +709,21 @@ erpnext.utils.map_current_doc = function(opts) {
setters: opts.setters,
get_query: opts.get_query,
add_filters_group: 1,
+ allow_child_item_selection: opts.allow_child_item_selection,
+ child_fieldname: opts.child_fielname,
+ child_columns: opts.child_columns,
+ size: opts.size,
action: function(selections, args) {
let values = selections;
- if(values.length === 0){
+ if (values.length === 0) {
frappe.msgprint(__("Please select {0}", [opts.source_doctype]))
return;
}
opts.source_name = values;
- opts.setters = args;
+ if (opts.allow_child_item_selection) {
+ // args contains filtered child docnames
+ opts.args = args;
+ }
d.dialog.hide();
_map();
},
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 490a7c4af73..fef1e76154f 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -31,6 +31,14 @@ body.product-page {
.carousel-control-prev,
.carousel-control-next {
opacity: 1;
+ width: 8%;
+
+ @media (max-width: 1200px) {
+ width: 10%;
+ }
+ @media (max-width: 768px) {
+ width: 15%;
+ }
}
.carousel-body {
@@ -43,6 +51,8 @@ body.product-page {
.carousel-content {
max-width: 400px;
+ margin-left: 5rem;
+ margin-right: 5rem;
}
.card {
diff --git a/erpnext/quality_management/workspace/quality/quality.json b/erpnext/quality_management/workspace/quality/quality.json
index 4dc8129d890..ae284701824 100644
--- a/erpnext/quality_management/workspace/quality/quality.json
+++ b/erpnext/quality_management/workspace/quality/quality.json
@@ -1,20 +1,13 @@
{
- "category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Goal\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Procedure\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Inspection\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Review\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Action\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Conformance\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Goal and Procedure\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Feedback\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Meeting\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Review and Action\", \"col\": 4}}]",
"creation": "2020-03-02 15:49:28.632014",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "quality",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Quality",
"links": [
{
@@ -149,15 +142,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:01.699912",
+ "modified": "2021-08-05 12:16:01.699913",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality",
- "onboarding": "",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index 45a689efa8b..d7dcbf4fe18 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -31,3 +31,4 @@ def create_transaction_log(doc, method):
"document_name": doc.name,
"data": data
}).insert(ignore_permissions=True)
+
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
index 95b930c4c86..fc579d4b38c 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.json
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -6,8 +6,10 @@
"engine": "InnoDB",
"field_order": [
"gst_summary",
- "column_break_2",
+ "gst_tax_settings_section",
"round_off_gst_values",
+ "column_break_4",
+ "hsn_wise_tax_breakup",
"gstin_email_sent_on",
"section_break_4",
"gst_accounts",
@@ -17,37 +19,23 @@
{
"fieldname": "gst_summary",
"fieldtype": "HTML",
- "label": "GST Summary",
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
+ "label": "GST Summary"
},
{
"fieldname": "gstin_email_sent_on",
"fieldtype": "Date",
"label": "GSTIN Email Sent On",
- "read_only": 1,
- "show_days": 1,
- "show_seconds": 1
+ "read_only": 1
},
{
"fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "show_days": 1,
- "show_seconds": 1
+ "fieldtype": "Section Break"
},
{
"fieldname": "gst_accounts",
"fieldtype": "Table",
"label": "GST Accounts",
- "options": "GST Account",
- "show_days": 1,
- "show_seconds": 1
+ "options": "GST Account"
},
{
"default": "250000",
@@ -56,24 +44,35 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "B2C Limit",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"default": "0",
"description": "Enabling this option will round off individual GST components in all the Invoices",
"fieldname": "round_off_gst_values",
"fieldtype": "Check",
- "label": "Round Off GST Values",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Round Off GST Values"
+ },
+ {
+ "default": "0",
+ "fieldname": "hsn_wise_tax_breakup",
+ "fieldtype": "Check",
+ "label": "Tax Breakup Table Based On HSN Code"
+ },
+ {
+ "fieldname": "gst_tax_settings_section",
+ "fieldtype": "Section Break",
+ "label": "GST Tax Settings"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-01-28 17:19:47.969260",
+ "modified": "2021-10-11 18:10:14.242614",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Settings",
@@ -83,4 +82,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
- }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/dosage_strength/__init__.py b/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/dosage_strength/__init__.py
rename to erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py
diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json
new file mode 100644
index 00000000000..89ba3e977af
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json
@@ -0,0 +1,49 @@
+{
+ "actions": [],
+ "creation": "2021-07-13 09:17:09.862163",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "item_tax_template",
+ "account"
+ ],
+ "fields": [
+ {
+ "fieldname": "account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Account",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Title",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_tax_template",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Tax Template",
+ "options": "Item Tax Template",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-08-04 06:42:38.205597",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "KSA VAT Purchase Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py
new file mode 100644
index 00000000000..3920bc546c1
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Havenir Solutions and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class KSAVATPurchaseAccount(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/drug_prescription/__init__.py b/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/drug_prescription/__init__.py
rename to erpnext/regional/doctype/ksa_vat_sales_account/__init__.py
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js
new file mode 100644
index 00000000000..72613f4064f
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Havenir Solutions and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('KSA VAT Sales Account', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json
new file mode 100644
index 00000000000..df2747891dc
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json
@@ -0,0 +1,49 @@
+{
+ "actions": [],
+ "creation": "2021-07-13 08:46:33.820968",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "item_tax_template",
+ "account"
+ ],
+ "fields": [
+ {
+ "fieldname": "account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Account",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Title",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_tax_template",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Tax Template",
+ "options": "Item Tax Template",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-08-04 06:42:00.081407",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "KSA VAT Sales Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py
new file mode 100644
index 00000000000..7c2689f530e
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Havenir Solutions and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class KSAVATSalesAccount(Document):
+ pass
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py
new file mode 100644
index 00000000000..1d6a6a793dc
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Havenir Solutions and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestKSAVATSalesAccount(unittest.TestCase):
+ pass
diff --git a/erpnext/healthcare/doctype/exercise/__init__.py b/erpnext/regional/doctype/ksa_vat_setting/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/exercise/__init__.py
rename to erpnext/regional/doctype/ksa_vat_setting/__init__.py
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js
new file mode 100644
index 00000000000..00b62b9adfb
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Havenir Solutions and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('KSA VAT Setting', {
+ onload: function () {
+ frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting');
+ }
+});
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json
new file mode 100644
index 00000000000..33619467ed0
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json
@@ -0,0 +1,49 @@
+{
+ "actions": [],
+ "autoname": "field:company",
+ "creation": "2021-07-13 08:49:01.100356",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "ksa_vat_sales_accounts",
+ "ksa_vat_purchase_accounts"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "ksa_vat_sales_accounts",
+ "fieldtype": "Table",
+ "label": "KSA VAT Sales Accounts",
+ "options": "KSA VAT Sales Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "ksa_vat_purchase_accounts",
+ "fieldtype": "Table",
+ "label": "KSA VAT Purchase Accounts",
+ "options": "KSA VAT Purchase Account",
+ "reqd": 1
+ }
+ ],
+ "links": [],
+ "modified": "2021-08-26 04:29:06.499378",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "KSA VAT Setting",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "company",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py
new file mode 100644
index 00000000000..bdae1161fd7
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Havenir Solutions and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class KSAVATSetting(Document):
+ pass
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js
new file mode 100644
index 00000000000..269cbec5fb4
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js
@@ -0,0 +1,5 @@
+frappe.listview_settings['KSA VAT Setting'] = {
+ onload () {
+ frappe.breadcrumbs.add('Accounts');
+ }
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py
new file mode 100644
index 00000000000..7207901fd43
--- /dev/null
+++ b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Havenir Solutions and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestKSAVATSetting(unittest.TestCase):
+ pass
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
index f48fe6f4763..c32ab6bec24 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
@@ -7,7 +7,7 @@
"engine": "InnoDB",
"field_order": [
"certificate_details_section",
- "section_code",
+ "tax_withholding_category",
"fiscal_year",
"column_break_3",
"certificate_no",
@@ -33,13 +33,6 @@
"reqd": 1,
"unique": 1
},
- {
- "fieldname": "section_code",
- "fieldtype": "Select",
- "label": "Section Code",
- "options": "192\n193\n194\n194A\n194C\n194D\n194H\n194I\n194J\n194LA\n194LBB\n194LBC\n195",
- "reqd": 1
- },
{
"fieldname": "section_break_3",
"fieldtype": "Section Break",
@@ -123,13 +116,22 @@
"label": "Fiscal Year",
"options": "Fiscal Year",
"reqd": 1
+ },
+ {
+ "fieldname": "tax_withholding_category",
+ "fieldtype": "Link",
+ "label": "Tax Withholding Category",
+ "options": "Tax Withholding Category",
+ "reqd": 1
}
],
+ "index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-04-23 23:04:41.203721",
+ "modified": "2021-10-23 18:33:38.962622",
"modified_by": "Administrator",
"module": "Regional",
"name": "Lower Deduction Certificate",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index d8553f1d913..821e0171bbd 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -15,7 +15,7 @@ from erpnext.accounts.utils import get_fiscal_year
class LowerDeductionCertificate(Document):
def validate(self):
self.validate_dates()
- self.validate_supplier_against_section_code()
+ self.validate_supplier_against_tax_category()
def validate_dates(self):
if getdate(self.valid_upto) < getdate(self.valid_from):
@@ -31,12 +31,14 @@ class LowerDeductionCertificate(Document):
<= fiscal_year.year_end_date):
frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
- def validate_supplier_against_section_code(self):
- duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate', {'supplier': self.supplier, 'section_code': self.section_code}, ['name', 'valid_from', 'valid_upto'], as_dict=True)
+ def validate_supplier_against_tax_category(self):
+ duplicate_certificate = frappe.db.get_value('Lower Deduction Certificate',
+ {'supplier': self.supplier, 'tax_withholding_category': self.tax_withholding_category, 'name': ("!=", self.name)},
+ ['name', 'valid_from', 'valid_upto'], as_dict=True)
if duplicate_certificate and self.are_dates_overlapping(duplicate_certificate):
certificate_link = get_link_to_form('Lower Deduction Certificate', duplicate_certificate.name)
- frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against Section Code {2} for this time period.")
- .format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.section_code)))
+ frappe.throw(_("There is already a valid Lower Deduction Certificate {0} for Supplier {1} against category {2} for this time period.")
+ .format(certificate_link, frappe.bold(self.supplier), frappe.bold(self.tax_withholding_category)))
def are_dates_overlapping(self,duplicate_certificate):
valid_from = duplicate_certificate.valid_from
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 963c4075cd2..1cbb154125f 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -132,6 +132,10 @@ def make_property_setters(patch=False):
make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '')
def make_custom_fields(update=True):
+ custom_fields = get_custom_fields()
+ create_custom_fields(custom_fields, update=update)
+
+def get_custom_fields():
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description',
allow_on_submit=1, print_hide=1, fetch_if_empty=1)
@@ -165,12 +169,12 @@ def make_custom_fields(update=True):
dict(fieldname='gst_category', label='GST Category',
fieldtype='Select', insert_after='gst_section', print_hide=1,
options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
- fetch_from='customer.gst_category', fetch_if_empty=1),
+ fetch_from='customer.gst_category', fetch_if_empty=1, length=25),
dict(fieldname='export_type', label='Export Type',
fieldtype='Select', insert_after='gst_category', print_hide=1,
depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='customer.export_type',
- fetch_if_empty=1),
+ fetch_if_empty=1, length=25),
]
delivery_note_gst_category = [
@@ -181,18 +185,18 @@ def make_custom_fields(update=True):
]
invoice_gst_fields = [
- dict(fieldname='invoice_copy', label='Invoice Copy',
+ dict(fieldname='invoice_copy', label='Invoice Copy', length=30,
fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1,
options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier'),
- dict(fieldname='reverse_charge', label='Reverse Charge',
+ dict(fieldname='reverse_charge', label='Reverse Charge', length=2,
fieldtype='Select', insert_after='invoice_copy', print_hide=1,
options='Y\nN', default='N'),
- dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN',
+ dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN', length=15,
fieldtype='Data', insert_after='export_type', print_hide=1),
dict(fieldname='gst_col_break', fieldtype='Column Break', insert_after='ecommerce_gstin'),
dict(fieldname='reason_for_issuing_document', label='Reason For Issuing document',
fieldtype='Select', insert_after='gst_col_break', print_hide=1,
- depends_on='eval:doc.is_return==1',
+ depends_on='eval:doc.is_return==1', length=45,
options='\n01-Sales Return\n02-Post Sale Discount\n03-Deficiency in services\n04-Correction in Invoice\n05-Change in POS\n06-Finalization of Provisional assessment\n07-Others')
]
@@ -230,25 +234,25 @@ def make_custom_fields(update=True):
sales_invoice_gst_fields = [
dict(fieldname='billing_address_gstin', label='Billing Address GSTIN',
fieldtype='Data', insert_after='customer_address', read_only=1,
- fetch_from='customer_address.gstin', print_hide=1),
+ fetch_from='customer_address.gstin', print_hide=1, length=15),
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address_name',
- fetch_from='shipping_address_name.gstin', print_hide=1),
+ fetch_from='shipping_address_name.gstin', print_hide=1, length=15),
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='customer_gstin',
- print_hide=1, read_only=1),
+ print_hide=1, read_only=1, length=50),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
- fetch_from='company_address.gstin', print_hide=1, read_only=1),
+ fetch_from='company_address.gstin', print_hide=1, read_only=1, length=15),
]
sales_invoice_shipping_fields = [
dict(fieldname='port_code', label='Port Code',
fieldtype='Data', insert_after='reason_for_issuing_document', print_hide=1,
- depends_on="eval:doc.gst_category=='Overseas' "),
+ depends_on="eval:doc.gst_category=='Overseas' ", length=15),
dict(fieldname='shipping_bill_number', label=' Shipping Bill Number',
fieldtype='Data', insert_after='port_code', print_hide=1,
- depends_on="eval:doc.gst_category=='Overseas' "),
+ depends_on="eval:doc.gst_category=='Overseas' ", length=50),
dict(fieldname='shipping_bill_date', label='Shipping Bill Date',
fieldtype='Date', insert_after='shipping_bill_number', print_hide=1,
depends_on="eval:doc.gst_category=='Overseas' "),
@@ -354,7 +358,8 @@ def make_custom_fields(update=True):
'insert_after': 'transporter',
'fetch_from': 'transporter.gst_transporter_id',
'print_hide': 1,
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 20
},
{
'fieldname': 'driver',
@@ -370,7 +375,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Data',
'insert_after': 'driver',
'print_hide': 1,
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 30
},
{
'fieldname': 'vehicle_no',
@@ -378,7 +384,8 @@ def make_custom_fields(update=True):
'fieldtype': 'Data',
'insert_after': 'lr_no',
'print_hide': 1,
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 10
},
{
'fieldname': 'distance',
@@ -395,7 +402,7 @@ def make_custom_fields(update=True):
{
'fieldname': 'transporter_name',
'label': 'Transporter Name',
- 'fieldtype': 'Data',
+ 'fieldtype': 'Small Text',
'insert_after': 'transporter_col_break',
'fetch_from': 'transporter.name',
'read_only': 1,
@@ -409,12 +416,13 @@ def make_custom_fields(update=True):
'options': '\nRoad\nAir\nRail\nShip',
'insert_after': 'transporter_name',
'print_hide': 1,
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 5
},
{
'fieldname': 'driver_name',
'label': 'Driver Name',
- 'fieldtype': 'Data',
+ 'fieldtype': 'Small Text',
'insert_after': 'mode_of_transport',
'fetch_from': 'driver.full_name',
'print_hide': 1,
@@ -437,7 +445,8 @@ def make_custom_fields(update=True):
'default': 'Regular',
'insert_after': 'lr_date',
'print_hide': 1,
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 30
},
{
'fieldname': 'ewaybill',
@@ -446,7 +455,8 @@ def make_custom_fields(update=True):
'depends_on': 'eval:(doc.docstatus === 1)',
'allow_on_submit': 1,
'insert_after': 'tax_id',
- 'translatable': 0
+ 'translatable': 0,
+ 'length': 20
}
]
@@ -483,6 +493,7 @@ def make_custom_fields(update=True):
'Purchase Order': purchase_invoice_gst_fields,
'Purchase Receipt': purchase_invoice_gst_fields,
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
+ 'POS Invoice': sales_invoice_gst_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
'Payment Entry': payment_entry_fields,
'Journal Entry': journal_entry_fields,
@@ -501,6 +512,7 @@ def make_custom_fields(update=True):
'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
+ 'POS Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
@@ -602,11 +614,17 @@ def make_custom_fields(update=True):
fieldtype='Currency', insert_after='monthly_hra_exemption', read_only=1, depends_on='house_rent_payment_amount')
],
'Supplier': [
+ {
+ 'fieldname': 'pan',
+ 'label': 'PAN',
+ 'fieldtype': 'Data',
+ 'insert_after': 'supplier_type'
+ },
{
'fieldname': 'gst_transporter_id',
'label': 'GST Transporter ID',
'fieldtype': 'Data',
- 'insert_after': 'supplier_type',
+ 'insert_after': 'pan',
'depends_on': 'eval:doc.is_transporter'
},
{
@@ -628,11 +646,17 @@ def make_custom_fields(update=True):
}
],
'Customer': [
+ {
+ 'fieldname': 'pan',
+ 'label': 'PAN',
+ 'fieldtype': 'Data',
+ 'insert_after': 'customer_type'
+ },
{
'fieldname': 'gst_category',
'label': 'GST Category',
'fieldtype': 'Select',
- 'insert_after': 'customer_type',
+ 'insert_after': 'pan',
'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
'default': 'Unregistered'
},
@@ -661,9 +685,19 @@ def make_custom_fields(update=True):
'fieldtype': 'Data',
'insert_after': 'email'
}
+ ],
+ 'Finance Book': [
+ {
+ 'fieldname': 'for_income_tax',
+ 'label': 'For Income Tax',
+ 'fieldtype': 'Check',
+ 'insert_after': 'finance_book_name',
+ 'description': 'If the asset is put to use for less than 180 days, the first Depreciation Rate will be reduced by 50%.'
+ }
]
}
- create_custom_fields(custom_fields, update=update)
+
+ return custom_fields
def make_fixtures(company=None):
docs = []
@@ -750,7 +784,7 @@ def set_salary_components(docs):
def set_tax_withholding_category(company):
accounts = []
- fiscal_year = None
+ fiscal_year_details = None
abbr = frappe.get_value("Company", company, "abbr")
tds_account = frappe.get_value("Account", 'TDS Payable - {0}'.format(abbr), 'name')
@@ -758,11 +792,11 @@ def set_tax_withholding_category(company):
accounts = [dict(company=company, account=tds_account)]
try:
- fiscal_year = get_fiscal_year(today(), verbose=0, company=company)[0]
+ fiscal_year_details = get_fiscal_year(today(), verbose=0, company=company)
except FiscalYearError:
pass
- docs = get_tds_details(accounts, fiscal_year)
+ docs = get_tds_details(accounts, fiscal_year_details)
for d in docs:
if not frappe.db.exists("Tax Withholding Category", d.get("name")):
@@ -777,9 +811,10 @@ def set_tax_withholding_category(company):
if accounts:
doc.append("accounts", accounts[0])
- if fiscal_year:
+ if fiscal_year_details:
# if fiscal year don't match with any of the already entered data, append rate row
- fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
+ fy_exist = [k for k in doc.get('rates') if k.get('from_date') <= fiscal_year_details[1] \
+ and k.get('to_date') >= fiscal_year_details[2]]
if not fy_exist:
doc.append("rates", d.get('rates')[0])
@@ -802,149 +837,149 @@ def set_tds_account(docs, company):
}
])
-def get_tds_details(accounts, fiscal_year):
+def get_tds_details(accounts, fiscal_year_details):
# bootstrap default tax withholding sections
return [
dict(name="TDS - 194C - Company",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194C - Individual",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194C - No PAN / Invalid PAN",
category_name="Payment to Contractors (Single / Aggregate)",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 30000, "cumulative_threshold": 100000}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 100000}]),
dict(name="TDS - 194D - Company",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - Company Assessee",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - Individual",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194D - No PAN / Invalid PAN",
category_name="Insurance Commission",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - Company",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - Individual",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 1,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 1, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194DA - No PAN / Invalid PAN",
category_name="Non-exempt payments made under a life insurance policy",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 100000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 100000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - Company",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - Individual",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 5,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 5, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194H - No PAN / Invalid PAN",
category_name="Commission / Brokerage",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 15000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 15000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - Company",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - Individual",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent - No PAN / Invalid PAN",
category_name="Rent",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - Company",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - Individual",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 2,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 2, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194I - Rent/Machinery - No PAN / Invalid PAN",
category_name="Rent-Plant / Machinery",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 180000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 180000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - Company",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - Individual",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Professional Fees - No PAN / Invalid PAN",
category_name="Professional Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 30000, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 30000, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - Company",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - Individual",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194J - Director Fees - No PAN / Invalid PAN",
category_name="Director Fees",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 0, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 0, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - Company",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 2500, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - Individual",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 10,
- "single_threshold": 2500, "cumulative_threshold": 0}]),
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 10, "single_threshold": 2500, "cumulative_threshold": 0}]),
dict(name="TDS - 194 - Dividends - No PAN / Invalid PAN",
category_name="Dividends",
doctype="Tax Withholding Category", accounts=accounts,
- rates=[{"fiscal_year": fiscal_year, "tax_withholding_rate": 20,
- "single_threshold": 2500, "cumulative_threshold": 0}])
+ rates=[{"from_date": fiscal_year_details[1], "to_date": fiscal_year_details[2],
+ "tax_withholding_rate": 20, "single_threshold": 2500, "cumulative_threshold": 0}])
]
def create_gratuity_rule():
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index bf06d4a497d..0c87421012b 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -62,7 +62,7 @@ def validate_gstin_for_india(doc, method):
.format(doc.gst_state_number), title=_("Invalid GSTIN"))
def validate_pan_for_india(doc, method):
- if doc.get('country') != 'India' or not doc.pan:
+ if doc.get('country') != 'India' or not doc.get('pan'):
return
if not PAN_NUMBER_FORMAT.match(doc.pan):
@@ -112,12 +112,13 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
- if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
+ hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
+ if frappe.get_meta(item_doctype).has_field('gst_hsn_code') and hsn_wise_in_gst_settings:
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
else:
return [_("Item"), _("Taxable Amount")] + tax_accounts
-def get_itemised_tax_breakup_data(doc, account_wise=False):
+def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise)
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
@@ -125,28 +126,32 @@ def get_itemised_tax_breakup_data(doc, account_wise=False):
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
return itemised_tax, itemised_taxable_amount
- item_hsn_map = frappe._dict()
- for d in doc.items:
- item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
+ hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
+
+ tax_breakup_hsn_wise = hsn_wise or hsn_wise_in_gst_settings
+ if tax_breakup_hsn_wise:
+ item_hsn_map = frappe._dict()
+ for d in doc.items:
+ item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
hsn_tax = {}
for item, taxes in itemised_tax.items():
- hsn_code = item_hsn_map.get(item)
- hsn_tax.setdefault(hsn_code, frappe._dict())
+ item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
+ hsn_tax.setdefault(item_or_hsn, frappe._dict())
for tax_desc, tax_detail in taxes.items():
key = tax_desc
if account_wise:
key = tax_detail.get('tax_account')
- hsn_tax[hsn_code].setdefault(key, {"tax_rate": 0, "tax_amount": 0})
- hsn_tax[hsn_code][key]["tax_rate"] = tax_detail.get("tax_rate")
- hsn_tax[hsn_code][key]["tax_amount"] += tax_detail.get("tax_amount")
+ hsn_tax[item_or_hsn].setdefault(key, {"tax_rate": 0, "tax_amount": 0})
+ hsn_tax[item_or_hsn][key]["tax_rate"] = tax_detail.get("tax_rate")
+ hsn_tax[item_or_hsn][key]["tax_amount"] += tax_detail.get("tax_amount")
# set taxable amount
hsn_taxable_amount = frappe._dict()
for item in itemised_taxable_amount:
- hsn_code = item_hsn_map.get(item)
- hsn_taxable_amount.setdefault(hsn_code, 0)
- hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item)
+ item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
+ hsn_taxable_amount.setdefault(item_or_hsn, 0)
+ hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item)
return hsn_tax, hsn_taxable_amount
@@ -251,6 +256,9 @@ def is_internal_transfer(party_details, doctype):
elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
destination_gstin = party_details.supplier_gstin
+ if not destination_gstin or party_details.gstin:
+ return False
+
if party_details.gstin == destination_gstin:
return True
else:
@@ -440,7 +448,7 @@ def get_ewb_data(dt, dn):
data.itemList = []
data.totalValue = doc.total
- data = get_item_list(data, doc)
+ data = get_item_list(data, doc, hsn_wise=True)
disable_rounded = frappe.db.get_single_value('Global Defaults', 'disable_rounded_total')
data.totInvValue = doc.grand_total if disable_rounded else doc.rounded_total
@@ -551,7 +559,7 @@ def get_address_details(data, doc, company_address, billing_address, dispatch_ad
return data
-def get_item_list(data, doc):
+def get_item_list(data, doc, hsn_wise=False):
for attr in ['cgstValue', 'sgstValue', 'igstValue', 'cessValue', 'OthValue']:
data[attr] = 0
@@ -563,7 +571,7 @@ def get_item_list(data, doc):
'cess_account': ['cessRate', 'cessValue']
}
item_data_attrs = ['sgstRate', 'cgstRate', 'igstRate', 'cessRate', 'cessNonAdvol']
- hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True)
+ hsn_wise_charges, hsn_taxable_amount = get_itemised_tax_breakup_data(doc, account_wise=True, hsn_wise=hsn_wise)
for hsn_code, taxable_amount in hsn_taxable_amount.items():
item_data = frappe._dict()
if not hsn_code:
@@ -847,7 +855,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
if row.depreciation_method in ("Straight Line", "Manual"):
# if the Depreciation Schedule is being prepared for the first time
if not asset.flags.increase_in_asset_life:
- depreciation_amount = (flt(row.value_after_depreciation) -
+ depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) -
flt(row.expected_value_after_useful_life)) / depreciation_left
# if the Depreciation Schedule is being modified after Asset Repair
@@ -859,12 +867,13 @@ def get_depreciation_amount(asset, depreciable_value, row):
rate_of_depreciation = row.rate_of_depreciation
# if its the first depreciation
if depreciable_value == asset.gross_purchase_amount:
- # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
- diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
- if diff <= 180:
- rate_of_depreciation = rate_of_depreciation / 2
- frappe.msgprint(
- _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
+ if row.finance_book and frappe.db.get_value('Finance Book', row.finance_book, 'for_income_tax'):
+ # as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
+ diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
+ if diff <= 180:
+ rate_of_depreciation = rate_of_depreciation / 2
+ frappe.msgprint(
+ _('As per IT Act, the rate of depreciation for the first depreciation entry is reduced by 50%.'))
depreciation_amount = flt(depreciable_value * (flt(rate_of_depreciation) / 100))
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index ca0defa648a..7d401bab669 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -96,35 +96,36 @@ class Gstr1Report(object):
def get_b2c_data(self):
b2cs_output = {}
- for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
- invoice_details = self.invoices.get(inv)
- for rate, items in items_based_on_rate.items():
- place_of_supply = invoice_details.get("place_of_supply")
- ecommerce_gstin = invoice_details.get("ecommerce_gstin")
+ if self.invoices:
+ for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
+ invoice_details = self.invoices.get(inv)
+ for rate, items in items_based_on_rate.items():
+ place_of_supply = invoice_details.get("place_of_supply")
+ ecommerce_gstin = invoice_details.get("ecommerce_gstin")
- b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin),{
- "place_of_supply": "",
- "ecommerce_gstin": "",
- "rate": "",
- "taxable_value": 0,
- "cess_amount": 0,
- "type": "",
- "invoice_number": invoice_details.get("invoice_number"),
- "posting_date": invoice_details.get("posting_date"),
- "invoice_value": invoice_details.get("base_grand_total"),
- })
+ b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin), {
+ "place_of_supply": "",
+ "ecommerce_gstin": "",
+ "rate": "",
+ "taxable_value": 0,
+ "cess_amount": 0,
+ "type": "",
+ "invoice_number": invoice_details.get("invoice_number"),
+ "posting_date": invoice_details.get("posting_date"),
+ "invoice_value": invoice_details.get("base_grand_total"),
+ })
- row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
- row["place_of_supply"] = place_of_supply
- row["ecommerce_gstin"] = ecommerce_gstin
- row["rate"] = rate
- row["taxable_value"] += sum([abs(net_amount)
- for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items])
- row["cess_amount"] += flt(self.invoice_cess.get(inv), 2)
- row["type"] = "E" if ecommerce_gstin else "OE"
+ row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
+ row["place_of_supply"] = place_of_supply
+ row["ecommerce_gstin"] = ecommerce_gstin
+ row["rate"] = rate
+ row["taxable_value"] += sum([abs(net_amount)
+ for item_code, net_amount in self.invoice_items.get(inv).items() if item_code in items])
+ row["cess_amount"] += flt(self.invoice_cess.get(inv), 2)
+ row["type"] = "E" if ecommerce_gstin else "OE"
- for key, value in iteritems(b2cs_output):
- self.data.append(value)
+ for key, value in iteritems(b2cs_output):
+ self.data.append(value)
def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
row = []
@@ -171,12 +172,6 @@ class Gstr1Report(object):
self.invoices = frappe._dict()
conditions = self.get_conditions()
- company_gstins = get_company_gstin_number(self.filters.get('company'), all_gstins=True)
-
- self.filters.update({
- 'company_gstins': company_gstins
- })
-
invoice_data = frappe.db.sql("""
select
{select_columns}
@@ -212,7 +207,7 @@ class Gstr1Report(object):
if self.filters.get("type_of_business") == "B2B":
- conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1"
+ conditions += "AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') AND is_return != 1 AND is_debit_note !=1"
if self.filters.get("type_of_business") in ("B2C Large", "B2C Small"):
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
@@ -221,7 +216,7 @@ class Gstr1Report(object):
if self.filters.get("type_of_business") == "B2C Large":
conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
- AND grand_total > {0} AND is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
+ AND grand_total > {0} AND is_return != 1 AND is_debit_note !=1 AND gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "B2C Small":
conditions += """ AND (
@@ -234,13 +229,13 @@ class Gstr1Report(object):
elif self.filters.get("type_of_business") == "CDNR-UNREG":
b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
- AND ABS(grand_total) > {0} AND (is_return = 1 OR is_debit_note = 1)
- AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')""".format(flt(b2c_limit))
+ AND (is_return = 1 OR is_debit_note = 1)
+ AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')"""
elif self.filters.get("type_of_business") == "EXPORT":
conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
- conditions += " AND IFNULL(billing_address_gstin, '') NOT IN %(company_gstins)s"
+ conditions += " AND IFNULL(billing_address_gstin, '') != company_gstin"
return conditions
@@ -1050,6 +1045,7 @@ def get_company_gstin_number(company, address=None, all_gstins=False):
["Dynamic Link", "link_doctype", "=", "Company"],
["Dynamic Link", "link_name", "=", company],
["Dynamic Link", "parenttype", "=", "Address"],
+ ["gstin", "!=", '']
]
gstin = frappe.get_all("Address", filters=filters, pluck="gstin", order_by="is_primary_address desc")
if gstin and not all_gstins:
diff --git a/erpnext/healthcare/doctype/exercise_difficulty_level/__init__.py b/erpnext/regional/report/ksa_vat/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/exercise_difficulty_level/__init__.py
rename to erpnext/regional/report/ksa_vat/__init__.py
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js
new file mode 100644
index 00000000000..d46d260ac1e
--- /dev/null
+++ b/erpnext/regional/report/ksa_vat/ksa_vat.js
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, Havenir Solutions and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["KSA VAT"] = {
+ onload() {
+ frappe.breadcrumbs.add('Accounts');
+ },
+ "filters": [
+ {
+ "fieldname": "company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "reqd": 1,
+ "default": frappe.defaults.get_user_default("Company")
+ },
+ {
+ "fieldname": "from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
+ },
+ {
+ "fieldname": "to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "reqd": 1,
+ "default": frappe.datetime.get_today()
+ }
+ ],
+ "formatter": function(value, row, column, data, default_formatter) {
+ if (data
+ && (data.title=='VAT on Sales' || data.title=='VAT on Purchases')
+ && data.title==value) {
+ value = $(`
${value} `);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("
").parent().html();
+ return value
+ }else if (data.title=='Grand Total'){
+ if (data.title==value) {
+ value = $(`
${value} `);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("
").parent().html();
+ return value
+ }else{
+ value = default_formatter(value, row, column, data);
+ value = $(`
${value} `);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("
").parent().html();
+ console.log($value)
+ return value
+ }
+ }else{
+ value = default_formatter(value, row, column, data);
+ return value;
+ }
+ },
+};
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.json b/erpnext/regional/report/ksa_vat/ksa_vat.json
new file mode 100644
index 00000000000..036e2603103
--- /dev/null
+++ b/erpnext/regional/report/ksa_vat/ksa_vat.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-07-13 08:54:38.000949",
+ "disable_prepared_report": 1,
+ "disabled": 1,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-08-26 04:14:37.202594",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "KSA VAT",
+ "owner": "Administrator",
+ "prepared_report": 1,
+ "ref_doctype": "GL Entry",
+ "report_name": "KSA VAT",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "System Manager"
+ },
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py
new file mode 100644
index 00000000000..a42ebc9f7e5
--- /dev/null
+++ b/erpnext/regional/report/ksa_vat/ksa_vat.py
@@ -0,0 +1,176 @@
+# Copyright (c) 2013, Havenir Solutions and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import json
+
+import frappe
+from frappe import _
+from frappe.utils import get_url_to_list
+
+
+def execute(filters=None):
+ columns = columns = get_columns()
+ data = get_data(filters)
+ return columns, data
+
+def get_columns():
+ return [
+ {
+ "fieldname": "title",
+ "label": _("Title"),
+ "fieldtype": "Data",
+ "width": 300
+ },
+ {
+ "fieldname": "amount",
+ "label": _("Amount (SAR)"),
+ "fieldtype": "Currency",
+ "width": 150,
+ },
+ {
+ "fieldname": "adjustment_amount",
+ "label": _("Adjustment (SAR)"),
+ "fieldtype": "Currency",
+ "width": 150,
+ },
+ {
+ "fieldname": "vat_amount",
+ "label": _("VAT Amount (SAR)"),
+ "fieldtype": "Currency",
+ "width": 150,
+ }
+ ]
+
+def get_data(filters):
+ data = []
+
+ # Validate if vat settings exist
+ company = filters.get('company')
+ if frappe.db.exists('KSA VAT Setting', company) is None:
+ url = get_url_to_list('KSA VAT Setting')
+ frappe.msgprint(_('Create
KSA VAT Setting for this company').format(url))
+ return data
+
+ ksa_vat_setting = frappe.get_doc('KSA VAT Setting', company)
+
+ # Sales Heading
+ append_data(data, 'VAT on Sales', '', '', '')
+
+ grand_total_taxable_amount = 0
+ grand_total_taxable_adjustment_amount = 0
+ grand_total_tax = 0
+
+ for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts:
+ total_taxable_amount, total_taxable_adjustment_amount, \
+ total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Sales Invoice')
+
+ # Adding results to data
+ append_data(data, vat_setting.title, total_taxable_amount,
+ total_taxable_adjustment_amount, total_tax)
+
+ grand_total_taxable_amount += total_taxable_amount
+ grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount
+ grand_total_tax += total_tax
+
+ # Sales Grand Total
+ append_data(data, 'Grand Total', grand_total_taxable_amount,
+ grand_total_taxable_adjustment_amount, grand_total_tax)
+
+ # Blank Line
+ append_data(data, '', '', '', '')
+
+ # Purchase Heading
+ append_data(data, 'VAT on Purchases', '', '', '')
+
+ grand_total_taxable_amount = 0
+ grand_total_taxable_adjustment_amount = 0
+ grand_total_tax = 0
+
+ for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts:
+ total_taxable_amount, total_taxable_adjustment_amount, \
+ total_tax = get_tax_data_for_each_vat_setting(vat_setting, filters, 'Purchase Invoice')
+
+ # Adding results to data
+ append_data(data, vat_setting.title, total_taxable_amount,
+ total_taxable_adjustment_amount, total_tax)
+
+ grand_total_taxable_amount += total_taxable_amount
+ grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount
+ grand_total_tax += total_tax
+
+ # Purchase Grand Total
+ append_data(data, 'Grand Total', grand_total_taxable_amount,
+ grand_total_taxable_adjustment_amount, grand_total_tax)
+
+ return data
+
+def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype):
+ '''
+ (KSA, {filters}, 'Sales Invoice') => 500, 153, 10 \n
+ calculates and returns \n
+ total_taxable_amount, total_taxable_adjustment_amount, total_tax'''
+ from_date = filters.get('from_date')
+ to_date = filters.get('to_date')
+
+ # Initiate variables
+ total_taxable_amount = 0
+ total_taxable_adjustment_amount = 0
+ total_tax = 0
+ # Fetch All Invoices
+ invoices = frappe.get_list(doctype,
+ filters ={
+ 'docstatus': 1,
+ 'posting_date': ['between', [from_date, to_date]]
+ }, fields =['name', 'is_return'])
+
+ for invoice in invoices:
+ invoice_items = frappe.get_list(f'{doctype} Item',
+ filters ={
+ 'docstatus': 1,
+ 'parent': invoice.name,
+ 'item_tax_template': vat_setting.item_tax_template
+ }, fields =['item_code', 'net_amount'])
+
+ for item in invoice_items:
+ # Summing up total taxable amount
+ if invoice.is_return == 0:
+ total_taxable_amount += item.net_amount
+
+ if invoice.is_return == 1:
+ total_taxable_adjustment_amount += item.net_amount
+
+ # Summing up total tax
+ total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name)
+
+ return total_taxable_amount, total_taxable_adjustment_amount, total_tax
+
+
+
+def append_data(data, title, amount, adjustment_amount, vat_amount):
+ """Returns data with appended value."""
+ data.append({"title": _(title), "amount": amount, "adjustment_amount": adjustment_amount, "vat_amount": vat_amount})
+
+def get_tax_amount(item_code, account_head, doctype, parent):
+ if doctype == 'Sales Invoice':
+ tax_doctype = 'Sales Taxes and Charges'
+
+ elif doctype == 'Purchase Invoice':
+ tax_doctype = 'Purchase Taxes and Charges'
+
+ item_wise_tax_detail = frappe.get_value(tax_doctype, {
+ 'docstatus': 1,
+ 'parent': parent,
+ 'account_head': account_head
+ }, 'item_wise_tax_detail')
+
+ tax_amount = 0
+ if item_wise_tax_detail and len(item_wise_tax_detail) > 0:
+ item_wise_tax_detail = json.loads(item_wise_tax_detail)
+ for key, value in item_wise_tax_detail.items():
+ if key == item_code:
+ tax_amount = value[1]
+ break
+
+ return tax_amount
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
index f4c049d1623..2b5ecc3b18c 100644
--- a/erpnext/regional/report/uae_vat_201/uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -122,7 +122,7 @@ def get_total_emiratewise(filters):
try:
return frappe.db.sql("""
select
- s.vat_emirate as emirate, sum(i.base_amount) as total, sum(s.total_taxes_and_charges)
+ s.vat_emirate as emirate, sum(i.base_amount) as total, sum(i.tax_amount)
from
`tabSales Invoice Item` i inner join `tabSales Invoice` s
on
diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py
index 9b3677d2c64..6113f48d3f1 100644
--- a/erpnext/regional/saudi_arabia/setup.py
+++ b/erpnext/regional/saudi_arabia/setup.py
@@ -2,10 +2,36 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
-from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats
-
+import frappe
+from frappe.permissions import add_permission, update_permission_property
+from erpnext.regional.united_arab_emirates.setup import make_custom_fields as uae_custom_fields, add_print_formats
+from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import create_ksa_vat_setting
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
def setup(company=None, patch=True):
- make_custom_fields()
+ uae_custom_fields()
add_print_formats()
+ add_permissions()
+ create_ksa_vat_setting(company)
+ make_qrcode_field()
+
+def add_permissions():
+ """Add Permissions for KSA VAT Setting."""
+ add_permission('KSA VAT Setting', 'All', 0)
+ for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
+ add_permission('KSA VAT Setting', role, 0)
+ update_permission_property('KSA VAT Setting', role, 0, 'write', 1)
+ update_permission_property('KSA VAT Setting', role, 0, 'create', 1)
+
+ """Enable KSA VAT Report"""
+ frappe.db.set_value('Report', 'KSA VAT', 'disabled', 0)
+
+def make_qrcode_field():
+ """Created QR code Image file"""
+ qr_code_field = dict(
+ fieldname='qr_code',
+ label='QR Code',
+ fieldtype='Attach Image',
+ read_only=1, no_copy=1, hidden=1)
+
+ create_custom_field('Sales Invoice', qr_code_field)
diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py
new file mode 100644
index 00000000000..cc6c0af7a56
--- /dev/null
+++ b/erpnext/regional/saudi_arabia/utils.py
@@ -0,0 +1,77 @@
+import io
+import os
+
+import frappe
+from pyqrcode import create as qr_create
+
+from erpnext import get_region
+
+
+def create_qr_code(doc, method):
+ """Create QR Code after inserting Sales Inv
+ """
+
+ region = get_region(doc.company)
+ if region not in ['Saudi Arabia']:
+ return
+
+ # if QR Code field not present, do nothing
+ if not hasattr(doc, 'qr_code'):
+ return
+
+ # Don't create QR Code if it already exists
+ qr_code = doc.get("qr_code")
+ if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}):
+ return
+
+ meta = frappe.get_meta('Sales Invoice')
+
+ for field in meta.get_image_fields():
+ if field.fieldname == 'qr_code':
+ # Creating public url to print format
+ default_print_format = frappe.db.get_value('Property Setter', dict(property='default_print_format', doc_type=doc.doctype), "value")
+
+ # System Language
+ language = frappe.get_system_settings('language')
+
+ # creating qr code for the url
+ url = f"{ frappe.utils.get_url() }/{ doc.doctype }/{ doc.name }?format={ default_print_format or 'Standard' }&_lang={ language }&key={ doc.get_signature() }"
+ qr_image = io.BytesIO()
+ url = qr_create(url, error='L')
+ url.png(qr_image, scale=2, quiet_zone=1)
+
+ # making file
+ filename = f"QR-CODE-{doc.name}.png".replace(os.path.sep, "__")
+ _file = frappe.get_doc({
+ "doctype": "File",
+ "file_name": filename,
+ "is_private": 0,
+ "content": qr_image.getvalue(),
+ "attached_to_doctype": doc.get("doctype"),
+ "attached_to_name": doc.get("name"),
+ "attached_to_field": "qr_code"
+ })
+
+ _file.save()
+
+ # assigning to document
+ doc.db_set('qr_code', _file.file_url)
+ doc.notify_update()
+
+ break
+
+
+def delete_qr_code_file(doc, method):
+ """Delete QR Code on deleted sales invoice"""
+
+ region = get_region(doc.company)
+ if region not in ['Saudi Arabia']:
+ return
+
+ if hasattr(doc, 'qr_code'):
+ if doc.get('qr_code'):
+ file_doc = frappe.get_list('File', {
+ 'file_url': doc.get('qr_code')
+ })
+ if len(file_doc):
+ frappe.delete_doc('File', file_doc[0].name)
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/exercise_type/__init__.py b/erpnext/regional/saudi_arabia/wizard/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/exercise_type/__init__.py
rename to erpnext/regional/saudi_arabia/wizard/__init__.py
diff --git a/erpnext/healthcare/doctype/exercise_type_step/__init__.py b/erpnext/regional/saudi_arabia/wizard/data/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/exercise_type_step/__init__.py
rename to erpnext/regional/saudi_arabia/wizard/data/__init__.py
diff --git a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json
new file mode 100644
index 00000000000..709d65be041
--- /dev/null
+++ b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json
@@ -0,0 +1,47 @@
+[
+ {
+ "type": "Sales Account",
+ "accounts": [
+ {
+ "title": "Standard rated Sales",
+ "item_tax_template": "KSA VAT 5%",
+ "account": "VAT 5%"
+ },
+ {
+ "title": "Zero rated domestic sales",
+ "item_tax_template": "KSA VAT Zero",
+ "account": "VAT Zero"
+ },
+ {
+ "title": "Exempted sales",
+ "item_tax_template": "KSA VAT Exempted",
+ "account": "VAT Zero"
+ }
+ ]
+ },
+ {
+ "type": "Purchase Account",
+ "accounts": [
+ {
+ "title": "Standard rated domestic purchases",
+ "item_tax_template": "KSA VAT 5%",
+ "account": "VAT 5%"
+ },
+ {
+ "title": "Imports subject to VAT paid at customs",
+ "item_tax_template": "KSA Excise 50%",
+ "account": "Excise 50%"
+ },
+ {
+ "title": "Zero rated purchases",
+ "item_tax_template": "KSA VAT Zero",
+ "account": "VAT Zero"
+ },
+ {
+ "title": "Exempted purchases",
+ "item_tax_template": "KSA VAT Exempted",
+ "account": "VAT Zero"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/fee_validity/__init__.py b/erpnext/regional/saudi_arabia/wizard/operations/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/fee_validity/__init__.py
rename to erpnext/regional/saudi_arabia/wizard/operations/__init__.py
diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py
new file mode 100644
index 00000000000..3c89edd37ed
--- /dev/null
+++ b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py
@@ -0,0 +1,46 @@
+import json
+import os
+
+import frappe
+
+from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges
+
+
+def create_ksa_vat_setting(company):
+ """On creation of first company. Creates KSA VAT Setting"""
+
+ company = frappe.get_doc('Company', company)
+ setup_taxes_and_charges(company.name, company.country)
+
+ file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'ksa_vat_settings.json')
+ with open(file_path, 'r') as json_file:
+ account_data = json.load(json_file)
+
+ # Creating KSA VAT Setting
+ ksa_vat_setting = frappe.get_doc({
+ 'doctype': 'KSA VAT Setting',
+ 'company': company.name
+ })
+
+ for data in account_data:
+ if data['type'] == 'Sales Account':
+ for row in data['accounts']:
+ item_tax_template = row['item_tax_template']
+ account = row['account']
+ ksa_vat_setting.append('ksa_vat_sales_accounts', {
+ 'title': row['title'],
+ 'item_tax_template': f'{item_tax_template} - {company.abbr}',
+ 'account': f'{account} - {company.abbr}'
+ })
+
+ elif data['type'] == 'Purchase Account':
+ for row in data['accounts']:
+ item_tax_template = row['item_tax_template']
+ account = row['account']
+ ksa_vat_setting.append('ksa_vat_purchase_accounts', {
+ 'title': row['title'],
+ 'item_tax_template': f'{item_tax_template} - {company.abbr}',
+ 'account': f'{account} - {company.abbr}'
+ })
+
+ ksa_vat_setting.save()
diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py
index 9c183af1d13..cf78f927c59 100644
--- a/erpnext/regional/united_states/setup.py
+++ b/erpnext/regional/united_states/setup.py
@@ -14,30 +14,9 @@ def setup(company=None, patch=True):
setup_company_independent_fixtures(patch=patch)
def setup_company_independent_fixtures(company=None, patch=True):
- add_product_tax_categories()
make_custom_fields()
- add_permissions()
- frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False)
add_print_formats()
-# Product Tax categories imported from taxjar api
-def add_product_tax_categories():
- with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f:
- tax_categories = json.loads(f.read())
- create_tax_categories(tax_categories['categories'])
-
-def create_tax_categories(data):
- for d in data:
- tax_category = frappe.new_doc('Product Tax Category')
- tax_category.description = d.get("description")
- tax_category.product_tax_code = d.get("product_tax_code")
- tax_category.category_name = d.get("name")
- try:
- tax_category.db_insert()
- except frappe.DuplicateEntryError:
- pass
-
-
def make_custom_fields(update=True):
custom_fields = {
'Supplier': [
@@ -59,29 +38,10 @@ def make_custom_fields(update=True):
'Quotation': [
dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges',
label='Is customer exempted from sales tax?')
- ],
- 'Sales Invoice Item': [
- dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category',
- label='Product Tax Category', fetch_from='item_code.product_tax_category'),
- dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount',
- label='Tax Collectable', read_only=1),
- dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable',
- label='Taxable Amount', read_only=1)
- ],
- 'Item': [
- dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category',
- label='Product Tax Category')
]
}
create_custom_fields(custom_fields, update=update)
-def add_permissions():
- doctype = "Product Tax Category"
- for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'):
- add_permission(doctype, role, 0)
- update_permission_property(doctype, role, 0, 'write', 1)
- update_permission_property(doctype, role, 0, 'create', 1)
-
def add_print_formats():
frappe.reload_doc("regional", "print_format", "irs_1099_form")
frappe.db.set_value("Print Format", "IRS 1099 Form", "disabled", 0)
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index cb00019cf5b..4b0bbd5a114 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -116,14 +116,15 @@ frappe.ui.form.on("Customer", {
frappe.contacts.render_address_and_contact(frm);
// custom buttons
- frm.add_custom_button(__('Accounting Ledger'), function() {
- frappe.set_route('query-report', 'General Ledger',
- {party_type:'Customer', party:frm.doc.name});
- });
- frm.add_custom_button(__('Accounts Receivable'), function() {
+ frm.add_custom_button(__('Accounts Receivable'), function () {
frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name});
- });
+ }, __('View'));
+
+ frm.add_custom_button(__('Accounting Ledger'), function () {
+ frappe.set_route('query-report', 'General Ledger',
+ {party_type: 'Customer', party: frm.doc.name});
+ }, __('View'));
frm.add_custom_button(__('Pricing Rule'), function () {
erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name);
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 5913b849eb7..ae406306170 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -16,11 +16,9 @@
"customer_name",
"gender",
"customer_type",
- "pan",
"tax_withholding_category",
"default_bank_account",
"lead_name",
- "prospect",
"opportunity_name",
"image",
"column_break0",
@@ -214,7 +212,8 @@
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Represents Company",
- "options": "Company"
+ "options": "Company",
+ "unique": 1
},
{
"depends_on": "represents_company",
@@ -486,25 +485,12 @@
"fieldtype": "Check",
"label": "Allow Sales Invoice Creation Without Delivery Note"
},
- {
- "fieldname": "pan",
- "fieldtype": "Data",
- "label": "PAN"
- },
{
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"label": "Tax Withholding Category",
"options": "Tax Withholding Category"
},
- {
- "fieldname": "prospect",
- "fieldtype": "Link",
- "label": "Prospect",
- "no_copy": 1,
- "options": "Prospect",
- "print_hide": 1
- },
{
"fieldname": "opportunity_name",
"fieldtype": "Link",
@@ -518,12 +504,19 @@
"idx": 363,
"image_field": "image",
"index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-08-25 18:56:09.929905",
+ "links": [
+ {
+ "group": "Allowed Items",
+ "link_doctype": "Party Specific Item",
+ "link_fieldname": "party"
+ }
+ ],
+ "modified": "2021-10-20 22:07:52.485809",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
"name_case": "Title Case",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 4be8139d575..7adf2cd909f 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -14,7 +14,7 @@ from frappe.contacts.address_and_contact import (
)
from frappe.desk.reportview import build_match_conditions, get_filters_cond
from frappe.model.mapper import get_mapped_doc
-from frappe.model.naming import set_name_by_naming_series
+from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options
from frappe.model.rename_doc import update_linked_doctypes
from frappe.utils import cint, cstr, flt, get_formatted_email, today
from frappe.utils.user import get_users_with_role
@@ -40,8 +40,10 @@ class Customer(TransactionBase):
cust_master_name = frappe.defaults.get_global_default('cust_master_name')
if cust_master_name == 'Customer Name':
self.name = self.get_customer_name()
- else:
+ elif cust_master_name == 'Naming Series':
set_name_by_naming_series(self)
+ else:
+ self.name = set_name_from_naming_options(frappe.get_meta(self.doctype).autoname, self)
def get_customer_name(self):
diff --git a/erpnext/healthcare/doctype/fee_validity_reference/__init__.py b/erpnext/selling/doctype/party_specific_item/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/fee_validity_reference/__init__.py
rename to erpnext/selling/doctype/party_specific_item/__init__.py
diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.js b/erpnext/selling/doctype/party_specific_item/party_specific_item.js
new file mode 100644
index 00000000000..077b93631ec
--- /dev/null
+++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Party Specific Item', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.json b/erpnext/selling/doctype/party_specific_item/party_specific_item.json
new file mode 100644
index 00000000000..32b5d478bb5
--- /dev/null
+++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.json
@@ -0,0 +1,77 @@
+{
+ "actions": [],
+ "creation": "2021-08-27 19:28:07.559978",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "party_type",
+ "party",
+ "column_break_3",
+ "restrict_based_on",
+ "based_on_value"
+ ],
+ "fields": [
+ {
+ "fieldname": "party_type",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Party Type",
+ "options": "Customer\nSupplier",
+ "reqd": 1
+ },
+ {
+ "fieldname": "party",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Party Name",
+ "options": "party_type",
+ "reqd": 1
+ },
+ {
+ "fieldname": "restrict_based_on",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Restrict Items Based On",
+ "options": "Item\nItem Group\nBrand",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "based_on_value",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Based On Value",
+ "options": "restrict_based_on",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-09-14 13:27:58.612334",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Party Specific Item",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "party",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.py b/erpnext/selling/doctype/party_specific_item/party_specific_item.py
new file mode 100644
index 00000000000..a408af56420
--- /dev/null
+++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+
+class PartySpecificItem(Document):
+ def validate(self):
+ exists = frappe.db.exists({
+ 'doctype': 'Party Specific Item',
+ 'party_type': self.party_type,
+ 'party': self.party,
+ 'restrict_based_on': self.restrict_based_on,
+ 'based_on': self.based_on_value,
+ })
+ if exists:
+ frappe.throw(_("This item filter has already been applied for the {0}").format(self.party_type))
diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py
new file mode 100644
index 00000000000..874a3645929
--- /dev/null
+++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+import unittest
+
+import frappe
+
+from erpnext.controllers.queries import item_query
+
+test_dependencies = ['Item', 'Customer', 'Supplier']
+
+def create_party_specific_item(**args):
+ psi = frappe.new_doc("Party Specific Item")
+ psi.party_type = args.get('party_type')
+ psi.party = args.get('party')
+ psi.restrict_based_on = args.get('restrict_based_on')
+ psi.based_on_value = args.get('based_on_value')
+ psi.insert()
+
+class TestPartySpecificItem(unittest.TestCase):
+ def setUp(self):
+ self.customer = frappe.get_last_doc("Customer")
+ self.supplier = frappe.get_last_doc("Supplier")
+ self.item = frappe.get_last_doc("Item")
+
+ def test_item_query_for_customer(self):
+ create_party_specific_item(party_type='Customer', party=self.customer.name, restrict_based_on='Item', based_on_value=self.item.name)
+ filters = {'is_sales_item': 1, 'customer': self.customer.name}
+ items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False)
+ for item in items:
+ self.assertEqual(item[0], self.item.name)
+
+ def test_item_query_for_supplier(self):
+ create_party_specific_item(party_type='Supplier', party=self.supplier.name, restrict_based_on='Item Group', based_on_value=self.item.item_group)
+ filters = {'supplier': self.supplier.name, 'is_purchase_item': 1}
+ items = item_query(doctype= 'Item', txt= '', searchfield= 'name', start= 0, page_len= 20,filters=filters, as_dict= False)
+ for item in items:
+ self.assertEqual(item[2], self.item.item_group)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index f6926906b82..d46c46f90e6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -78,6 +78,8 @@ frappe.ui.form.on("Sales Order", {
});
erpnext.queries.setup_warehouse_query(frm);
+
+ frm.ignore_doctypes_on_cancel_all = ['Purchase Order'];
},
delivery_date: function(frm) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 85282ca1a07..7c7ed9a9604 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1480,6 +1480,7 @@
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1512,7 +1513,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-09-01 15:12:24.115483",
+ "modified": "2021-09-28 13:09:51.515542",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 93676094218..dcf478bda6e 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -110,7 +110,7 @@ class SalesOrder(SellingController):
if self.order_type == 'Sales' and not self.skip_delivery_note:
delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date]
max_delivery_date = max(delivery_date_list) if delivery_date_list else None
- if not self.delivery_date:
+ if (max_delivery_date and not self.delivery_date) or (max_delivery_date and getdate(self.delivery_date) != getdate(max_delivery_date)):
self.delivery_date = max_delivery_date
if self.delivery_date:
for d in self.get("items"):
@@ -119,8 +119,6 @@ class SalesOrder(SellingController):
if getdate(self.transaction_date) > getdate(d.delivery_date):
frappe.msgprint(_("Expected Delivery Date should be after Sales Order Date"),
indicator='orange', title=_('Warning'))
- if getdate(self.delivery_date) != getdate(max_delivery_date):
- self.delivery_date = max_delivery_date
else:
frappe.throw(_("Please enter Delivery Date"))
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index bbfe7c06d87..222e74ee6c5 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1382,7 +1382,6 @@ def make_sales_order_workflow():
frappe.get_doc(dict(doctype='Role', role_name='Test Junior Approver')).insert(ignore_if_duplicate=True)
frappe.get_doc(dict(doctype='Role', role_name='Test Approver')).insert(ignore_if_duplicate=True)
- frappe.db.commit()
frappe.cache().hdel('roles', frappe.session.user)
workflow = frappe.get_doc({
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 59fcb982819..c27f1ea81ad 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -41,14 +41,14 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Customer Naming By",
- "options": "Customer Name\nNaming Series"
+ "options": "Customer Name\nNaming Series\nAuto Name"
},
{
"fieldname": "campaign_naming_by",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Campaign Naming By",
- "options": "Campaign Name\nNaming Series"
+ "options": "Campaign Name\nNaming Series\nAuto Name"
},
{
"fieldname": "customer_group",
@@ -204,7 +204,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-09-01 22:55:33.803624",
+ "modified": "2021-09-08 19:38:10.175989",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
@@ -223,4 +223,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js
index d899c5c19b4..ec861d7c531 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -236,7 +236,7 @@ erpnext.PointOfSale.ItemDetails = class {
if (this.value) {
me.events.form_updated(me.current_item, 'warehouse', this.value).then(() => {
me.item_stock_map = me.events.get_item_stock_map();
- const available_qty = me.item_stock_map[me.item_row.item_code][this.value];
+ const available_qty = me.item_stock_map[me.item_row.item_code] && me.item_stock_map[me.item_row.item_code][this.value];
if (available_qty === undefined) {
me.events.get_available_stock(me.item_row.item_code, this.value).then(() => {
// item stock map is updated now reset warehouse
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 8e69851213f..7ddbf45fdb8 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -297,6 +297,7 @@ erpnext.PointOfSale.Payment = class {
this.render_payment_mode_dom();
this.make_invoice_fields_control();
this.update_totals_section();
+ this.focus_on_default_mop();
}
edit_cart() {
@@ -378,17 +379,24 @@ erpnext.PointOfSale.Payment = class {
});
this[`${mode}_control`].toggle_label(false);
this[`${mode}_control`].set_value(p.amount);
+ });
+ this.render_loyalty_points_payment_mode();
+
+ this.attach_cash_shortcuts(doc);
+ }
+
+ focus_on_default_mop() {
+ const doc = this.events.get_frm().doc;
+ const payments = doc.payments;
+ payments.forEach(p => {
+ const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase();
if (p.default) {
setTimeout(() => {
this.$payment_modes.find(`.${mode}.mode-of-payment-control`).parent().click();
}, 500);
}
});
-
- this.render_loyalty_points_payment_mode();
-
- this.attach_cash_shortcuts(doc);
}
attach_cash_shortcuts(doc) {
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/__init__.py b/erpnext/selling/print_format_field_template/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/healthcare_practitioner/__init__.py
rename to erpnext/selling/print_format_field_template/__init__.py
diff --git a/erpnext/healthcare/doctype/healthcare_schedule_time_slot/__init__.py b/erpnext/selling/print_format_field_template/quotation_taxes/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/healthcare_schedule_time_slot/__init__.py
rename to erpnext/selling/print_format_field_template/quotation_taxes/__init__.py
diff --git a/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json
new file mode 100644
index 00000000000..eaa17cedf05
--- /dev/null
+++ b/erpnext/selling/print_format_field_template/quotation_taxes/quotation_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 15:48:56.416449",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Quotation",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:11:33.553722",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Quotation Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/__init__.py b/erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/healthcare_service_unit/__init__.py
rename to erpnext/selling/print_format_field_template/sales_order_taxes/__init__.py
diff --git a/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json
new file mode 100644
index 00000000000..2aacb440ff8
--- /dev/null
+++ b/erpnext/selling/print_format_field_template/sales_order_taxes/sales_order_taxes.json
@@ -0,0 +1,16 @@
+{
+ "creation": "2021-10-19 18:04:24.443076",
+ "docstatus": 0,
+ "doctype": "Print Format Field Template",
+ "document_type": "Sales Order",
+ "field": "taxes",
+ "idx": 0,
+ "modified": "2021-10-19 18:04:24.443076",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Sales Order Taxes",
+ "owner": "Administrator",
+ "standard": 1,
+ "template": "",
+ "template_file": "templates/print_formats/includes/taxes_and_charges.html"
+}
\ No newline at end of file
diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
index 805c3d804fa..5c4d8b601f4 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -73,7 +73,7 @@ def get_data(conditions, filters):
`tabSales Order` so,
`tabSales Order Item` soi
LEFT JOIN `tabSales Invoice Item` sii
- ON sii.so_detail = soi.name
+ ON sii.so_detail = soi.name and sii.docstatus = 1
WHERE
soi.parent = so.name
and so.status not in ('Stopped', 'Closed', 'On Hold')
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 955ef5e9396..a86e60494e8 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -63,7 +63,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
this.frm.set_query("item_code", "items", function() {
return {
query: "erpnext.controllers.queries.item_query",
- filters: {'is_sales_item': 1}
+ filters: {'is_sales_item': 1, 'customer': cur_frm.doc.customer}
}
});
}
@@ -206,8 +206,10 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
var me = this;
var item = frappe.get_doc(cdt, cdn);
- if (item.serial_no && item.qty === item.serial_no.split(`\n`).length) {
- return;
+ // check if serial nos entered are as much as qty in row
+ if (item.serial_no) {
+ let serial_nos = item.serial_no.split(`\n`).filter(sn => sn.trim()); // filter out whitespaces
+ if (item.qty === serial_nos.length) return;
}
if (item.serial_no && !item.batch_no) {
@@ -247,7 +249,12 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate"));
if(df && editable_price_list_rate) {
- df.read_only = 0;
+ const parent_field = frappe.meta.get_parentfield(this.frm.doc.doctype, this.frm.doc.doctype + " Item");
+ if (!this.frm.fields_dict[parent_field]) return;
+
+ this.frm.fields_dict[parent_field].grid.update_docfield_property(
+ 'price_list_rate', 'read_only', 0
+ );
}
}
diff --git a/erpnext/selling/workspace/retail/retail.json b/erpnext/selling/workspace/retail/retail.json
index 9d2e6cabbc3..a851ace738c 100644
--- a/erpnext/selling/workspace/retail/retail.json
+++ b/erpnext/selling/workspace/retail/retail.json
@@ -1,20 +1,13 @@
{
- "category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Point Of Sale\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings & Configurations\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loyalty Program\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Opening & Closing\", \"col\": 4}}]",
"creation": "2020-03-02 17:18:32.505616",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "retail",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Retail",
"links": [
{
@@ -108,15 +101,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:01.840988",
+ "modified": "2021-08-05 12:16:01.840989",
"modified_by": "Administrator",
"module": "Selling",
"name": "Retail",
- "onboarding": "",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "Retail",
"roles": [],
diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json
index 345187f93c4..db2e6bafd55 100644
--- a/erpnext/selling/workspace/selling/selling.json
+++ b/erpnext/selling/workspace/selling/selling.json
@@ -1,26 +1,18 @@
{
- "category": "",
"charts": [
{
"chart_name": "Sales Order Trends",
"label": "Sales Order Trends"
}
],
- "charts_label": "Selling ",
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Selling\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Sales Order Trends\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Quick Access\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Order Analysis\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Selling\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Items and Pricing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]",
"creation": "2020-01-28 11:49:12.092882",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "sell",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Selling",
"links": [
{
@@ -570,15 +562,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:01.990702",
+ "modified": "2021-08-05 12:16:01.990703",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling",
- "onboarding": "Selling",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
@@ -619,6 +608,5 @@
"type": "Dashboard"
}
],
- "shortcuts_label": "Quick Access",
"title": "Selling"
}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 8403193df53..95ca3867ee7 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -46,43 +46,6 @@ frappe.ui.form.on("Company", {
});
},
- change_abbreviation(frm) {
- var dialog = new frappe.ui.Dialog({
- title: "Replace Abbr",
- fields: [
- {"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
- "reqd": 1 },
- {"fieldtype": "Button", "label": "Update", "fieldname": "update"},
- ]
- });
-
- dialog.fields_dict.update.$input.click(function() {
- var args = dialog.get_values();
- if (!args) return;
- frappe.show_alert(__("Update in progress. It might take a while."));
- return frappe.call({
- method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
- args: {
- "company": frm.doc.name,
- "old": frm.doc.abbr,
- "new": args.new_abbr
- },
- callback: function(r) {
- if (r.exc) {
- frappe.msgprint(__("There were errors."));
- return;
- } else {
- frm.set_value("abbr", args.new_abbr);
- }
- dialog.hide();
- frm.refresh();
- },
- btn: this
- });
- });
- dialog.show();
- },
-
company_name: function(frm) {
if(frm.doc.__islocal) {
// add missing " " arg in split method
@@ -164,10 +127,6 @@ frappe.ui.form.on("Company", {
}, __('Manage'));
}
}
-
- frm.add_custom_button(__('Change Abbreviation'), () => {
- frm.trigger('change_abbreviation');
- }, __('Manage'));
}
erpnext.company.set_chart_of_accounts_options(frm.doc);
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 58cb52c04dd..63d96bf85e7 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -125,7 +125,8 @@
"label": "Abbr",
"oldfieldname": "abbr",
"oldfieldtype": "Data",
- "reqd": 1
+ "reqd": 1,
+ "set_only_once": 1
},
{
"bold": 1,
@@ -747,10 +748,11 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
- "modified": "2021-07-12 11:27:06.353860",
+ "modified": "2021-10-04 12:09:25.833133",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
+ "naming_rule": "By fieldname",
"nsm_parent_field": "parent_company",
"owner": "Administrator",
"permissions": [
@@ -808,4 +810,4 @@
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 6257d560ec8..0b1b4a1ec02 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -388,6 +388,7 @@ class Company(NestedSet):
frappe.db.sql("delete from tabEmployee where company=%s", self.name)
frappe.db.sql("delete from tabDepartment where company=%s", self.name)
frappe.db.sql("delete from `tabTax Withholding Account` where company=%s", self.name)
+ frappe.db.sql("delete from `tabTransaction Deletion Record` where company=%s", self.name)
# delete tax templates
frappe.db.sql("delete from `tabSales Taxes and Charges Template` where company=%s", self.name)
@@ -398,44 +399,6 @@ class Company(NestedSet):
if not frappe.db.get_value('GL Entry', {'company': self.name}):
frappe.db.sql("delete from `tabProcess Deferred Accounting` where company=%s", self.name)
-@frappe.whitelist()
-def enqueue_replace_abbr(company, old, new):
- kwargs = dict(queue="long", company=company, old=old, new=new)
- frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs)
-
-
-@frappe.whitelist()
-def replace_abbr(company, old, new):
- new = new.strip()
- if not new:
- frappe.throw(_("Abbr can not be blank or space"))
-
- frappe.only_for("System Manager")
-
- def _rename_record(doc):
- parts = doc[0].rsplit(" - ", 1)
- if len(parts) == 1 or parts[1].lower() == old.lower():
- frappe.rename_doc(dt, doc[0], parts[0] + " - " + new, force=True)
-
- def _rename_records(dt):
- # rename is expensive so let's be economical with memory usage
- doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company))
- for d in doc:
- _rename_record(d)
- try:
- frappe.db.auto_commit_on_many_writes = 1
- for dt in ["Warehouse", "Account", "Cost Center", "Department",
- "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
- _rename_records(dt)
- frappe.db.commit()
- frappe.db.set_value("Company", company, "abbr", new)
-
- except Exception:
- frappe.log_error(title=_('Abbreviation Rename Error'))
- finally:
- frappe.db.auto_commit_on_many_writes = 0
-
-
def get_name_with_abbr(name, company):
company_abbr = frappe.get_cached_value('Company', company, "abbr")
parts = name.split(" - ")
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index ddf3e662e0c..ab50a58c4fb 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -39,6 +39,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
self.parent_item_group = _('All Item Groups')
self.make_route()
+ self.validate_item_group_defaults()
def on_update(self):
NestedSet.on_update(self)
@@ -99,7 +100,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
filter_engine = ProductFiltersBuilder(self.name)
context.field_filters = filter_engine.get_field_filters()
- context.attribute_filters = filter_engine.get_attribute_fitlers()
+ context.attribute_filters = filter_engine.get_attribute_filters()
context.update({
"parents": get_parent_item_groups(self.parent_item_group),
@@ -134,6 +135,10 @@ class ItemGroup(NestedSet, WebsiteGenerator):
def delete_child_item_groups_key(self):
frappe.cache().hdel("child_item_groups", self.name)
+ def validate_item_group_defaults(self):
+ from erpnext.stock.doctype.item.item import validate_item_default_company_links
+ validate_item_default_company_links(self.item_group_defaults)
+
@frappe.whitelist(allow_guest=True)
def get_product_list_for_group(product_group=None, start=0, limit=10, search=None):
if product_group:
diff --git a/erpnext/setup/doctype/item_group/test_records.json b/erpnext/setup/doctype/item_group/test_records.json
index 146da87bddc..ce1d718375a 100644
--- a/erpnext/setup/doctype/item_group/test_records.json
+++ b/erpnext/setup/doctype/item_group/test_records.json
@@ -1,73 +1,74 @@
[
{
- "doctype": "Item Group",
- "is_group": 0,
- "item_group_name": "_Test Item Group",
+ "doctype": "Item Group",
+ "is_group": 0,
+ "item_group_name": "_Test Item Group",
"parent_item_group": "All Item Groups",
"item_group_defaults": [{
"company": "_Test Company",
"buying_cost_center": "_Test Cost Center 2 - _TC",
- "selling_cost_center": "_Test Cost Center 2 - _TC"
+ "selling_cost_center": "_Test Cost Center 2 - _TC",
+ "default_warehouse": "_Test Warehouse - _TC"
}]
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 0,
- "item_group_name": "_Test Item Group Desktops",
+ "doctype": "Item Group",
+ "is_group": 0,
+ "item_group_name": "_Test Item Group Desktops",
"parent_item_group": "All Item Groups"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group A",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group A",
"parent_item_group": "All Item Groups"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group B",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group B",
"parent_item_group": "All Item Groups"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group B - 1",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group B - 1",
"parent_item_group": "_Test Item Group B"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group B - 2",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group B - 2",
"parent_item_group": "_Test Item Group B"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 0,
- "item_group_name": "_Test Item Group B - 3",
+ "doctype": "Item Group",
+ "is_group": 0,
+ "item_group_name": "_Test Item Group B - 3",
"parent_item_group": "_Test Item Group B"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group C",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group C",
"parent_item_group": "All Item Groups"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group C - 1",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group C - 1",
"parent_item_group": "_Test Item Group C"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group C - 2",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group C - 2",
"parent_item_group": "_Test Item Group C"
- },
+ },
{
- "doctype": "Item Group",
- "is_group": 1,
- "item_group_name": "_Test Item Group D",
+ "doctype": "Item Group",
+ "is_group": 1,
+ "item_group_name": "_Test Item Group D",
"parent_item_group": "All Item Groups"
},
{
@@ -104,4 +105,4 @@
}
]
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/setup/doctype/uom/uom.json b/erpnext/setup/doctype/uom/uom.json
index 3a4e7f6dc4b..844a11f1397 100644
--- a/erpnext/setup/doctype/uom/uom.json
+++ b/erpnext/setup/doctype/uom/uom.json
@@ -1,164 +1,82 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:uom_name",
- "beta": 0,
"creation": "2013-01-10 16:34:24",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
+ "engine": "InnoDB",
+ "field_order": [
+ "enabled",
+ "uom_name",
+ "must_be_whole_number"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "uom_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "UOM Name",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "uom_name",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"description": "Check this to disallow fractions. (for Nos)",
"fieldname": "must_be_whole_number",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Must be Whole Number",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Must be Whole Number"
+ },
+ {
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "label": "Enabled"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-compass",
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-29 06:35:56.143361",
+ "links": [],
+ "modified": "2021-10-18 14:07:43.722144",
"modified_by": "Administrator",
"module": "Setup",
"name": "UOM",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Item Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock Manager"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock User"
}
],
"quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json
index 34af093a231..8a1338583ba 100644
--- a/erpnext/setup/setup_wizard/data/country_wise_tax.json
+++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json
@@ -1195,7 +1195,7 @@
"*": {
"item_tax_templates": [
{
- "title": "GST 9%",
+ "title": "GST 18%",
"taxes": [
{
"tax_type": {
@@ -2116,9 +2116,9 @@
},
"Saudi Arabia": {
- "KSA VAT 5%": {
- "account_name": "VAT 5%",
- "tax_rate": 5.00
+ "KSA VAT 15%": {
+ "account_name": "VAT 15%",
+ "tax_rate": 15.00
},
"KSA VAT Zero": {
"account_name": "VAT Zero",
diff --git a/erpnext/setup/setup_wizard/operations/defaults_setup.py b/erpnext/setup/setup_wizard/operations/defaults_setup.py
index 6dd0fb1403f..55d5ec8630e 100644
--- a/erpnext/setup/setup_wizard/operations/defaults_setup.py
+++ b/erpnext/setup/setup_wizard/operations/defaults_setup.py
@@ -62,6 +62,13 @@ def set_default_settings(args):
hr_settings.emp_created_by = "Naming Series"
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
hr_settings.leave_status_notification_template = _("Leave Status Notification")
+
+ hr_settings.send_interview_reminder = 1
+ hr_settings.interview_reminder_template = _("Interview Reminder")
+ hr_settings.remind_before = "00:15:00"
+
+ hr_settings.send_interview_feedback_reminder = 1
+ hr_settings.feedback_reminder_notification_template = _("Interview Feedback Reminder")
hr_settings.save()
def set_no_copy_fields_in_variant_settings():
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 907967c83fd..d61d94c3c69 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -202,7 +202,6 @@ def install(country=None):
{'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"},
{'doctype': "Party Type", "party_type": "Donor", "account_type": "Receivable"},
- {'doctype': "Opportunity Type", "name": "Hub"},
{'doctype': "Opportunity Type", "name": _("Sales")},
{'doctype': "Opportunity Type", "name": _("Support")},
{'doctype': "Opportunity Type", "name": _("Maintenance")},
@@ -264,16 +263,26 @@ def install(country=None):
base_path = frappe.get_app_path("erpnext", "hr", "doctype")
response = frappe.read_file(os.path.join(base_path, "leave_application/leave_application_email_template.html"))
- records += [{'doctype': 'Email Template', 'name': _("Leave Approval Notification"), 'response': response,\
+ records += [{'doctype': 'Email Template', 'name': _("Leave Approval Notification"), 'response': response,
'subject': _("Leave Approval Notification"), 'owner': frappe.session.user}]
- records += [{'doctype': 'Email Template', 'name': _("Leave Status Notification"), 'response': response,\
+ records += [{'doctype': 'Email Template', 'name': _("Leave Status Notification"), 'response': response,
'subject': _("Leave Status Notification"), 'owner': frappe.session.user}]
+ response = frappe.read_file(os.path.join(base_path, "interview/interview_reminder_notification_template.html"))
+
+ records += [{'doctype': 'Email Template', 'name': _('Interview Reminder'), 'response': response,
+ 'subject': _('Interview Reminder'), 'owner': frappe.session.user}]
+
+ response = frappe.read_file(os.path.join(base_path, "interview/interview_feedback_reminder_template.html"))
+
+ records += [{'doctype': 'Email Template', 'name': _('Interview Feedback Reminder'), 'response': response,
+ 'subject': _('Interview Feedback Reminder'), 'owner': frappe.session.user}]
+
base_path = frappe.get_app_path("erpnext", "stock", "doctype")
response = frappe.read_file(os.path.join(base_path, "delivery_trip/dispatch_notification_template.html"))
- records += [{'doctype': 'Email Template', 'name': _("Dispatch Notification"), 'response': response,\
+ records += [{'doctype': 'Email Template', 'name': _("Dispatch Notification"), 'response': response,
'subject': _("Your order is out for delivery!"), 'owner': frappe.session.user}]
# Records for the Supplier Scorecard
@@ -317,6 +326,14 @@ def update_hr_defaults():
hr_settings.emp_created_by = "Naming Series"
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
hr_settings.leave_status_notification_template = _("Leave Status Notification")
+
+ hr_settings.send_interview_reminder = 1
+ hr_settings.interview_reminder_template = _("Interview Reminder")
+ hr_settings.remind_before = "00:15:00"
+
+ hr_settings.send_interview_feedback_reminder = 1
+ hr_settings.feedback_reminder_notification_template = _("Interview Feedback Reminder")
+
hr_settings.save()
def update_item_variant_settings():
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index faa25dfbaa2..58a14d20f20 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -192,7 +192,7 @@ def get_or_create_account(company_name, account):
default_root_type = 'Liability'
root_type = account.get('root_type', default_root_type)
- existing_accounts = frappe.get_list('Account',
+ existing_accounts = frappe.get_all('Account',
filters={
'company': company_name,
'root_type': root_type
@@ -247,7 +247,7 @@ def get_or_create_tax_group(company_name, root_type):
# Create a new group account named 'Duties and Taxes' or 'Tax Assets' just
# below the root account
- root_account = frappe.get_list('Account', {
+ root_account = frappe.get_all('Account', {
'is_group': 1,
'root_type': root_type,
'company': company_name,
diff --git a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
index ef4b050ceb2..1412acfcead 100644
--- a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
+++ b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
@@ -1,31 +1,21 @@
{
- "category": "",
"charts": [],
- "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Projects Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Accounts Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"HR Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Selling Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Buying Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Support Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Shopping Cart Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Portal Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Manufacturing Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Education Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Hotel Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Domain Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Products Settings\", \"col\": 4}}]",
+ "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Projects Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Stock Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"HR Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Selling Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Buying Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Support Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Shopping Cart Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Portal Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Domain Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Products Settings\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Naming Series\",\"col\":4}}]",
"creation": "2020-03-12 14:47:51.166455",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "setting",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "ERPNext Settings",
"links": [],
- "modified": "2021-08-05 12:15:59.052327",
+ "modified": "2021-10-26 21:32:55.323591",
"modified_by": "Administrator",
"module": "Setup",
"name": "ERPNext Settings",
- "onboarding": "",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
@@ -37,6 +27,14 @@
"link_to": "Projects Settings",
"type": "DocType"
},
+ {
+ "color": "Grey",
+ "doc_view": "",
+ "icon": "dot-horizontal",
+ "label": "Naming Series",
+ "link_to": "Naming Series",
+ "type": "DocType"
+ },
{
"icon": "accounting",
"label": "Accounts Settings",
diff --git a/erpnext/setup/workspace/home/home.json b/erpnext/setup/workspace/home/home.json
index a4e7ad863b0..4e1ccf9b94f 100644
--- a/erpnext/setup/workspace/home/home.json
+++ b/erpnext/setup/workspace/home/home.json
@@ -1,20 +1,13 @@
{
- "category": "",
"charts": [],
- "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Supplier\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Leaderboard\",\"col\":4}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"level\":4,\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Stock\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Human Resources\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"CRM\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Data Import and Settings\",\"col\":4}}]",
+ "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"level\":4,\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Supplier\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":4}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Leaderboard\",\"col\":4}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"level\":4,\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Accounting\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Stock\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Human Resources\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"CRM\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Data Import and Settings\",\"col\":4}}]",
"creation": "2020-01-23 13:46:38.833076",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "getting-started",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Home",
"links": [
{
@@ -278,15 +271,12 @@
"type": "Link"
}
],
- "modified": "2021-08-10 15:33:20.704740",
+ "modified": "2021-08-10 15:33:20.704741",
"modified_by": "Administrator",
"module": "Setup",
"name": "Home",
- "onboarding": "",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
index f8a22b0e020..1164a5d3949 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -44,7 +44,6 @@ class TestShoppingCartSettings(unittest.TestCase):
def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
- frappe.db.commit()
cart_settings = self.get_cart_settings()
cart_settings.enabled = 1
diff --git a/erpnext/shopping_cart/filters.py b/erpnext/shopping_cart/filters.py
index aaeff0fe073..4787ae534cf 100644
--- a/erpnext/shopping_cart/filters.py
+++ b/erpnext/shopping_cart/filters.py
@@ -4,7 +4,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _dict
class ProductFiltersBuilder:
@@ -57,37 +56,31 @@ class ProductFiltersBuilder:
return filter_data
- def get_attribute_fitlers(self):
+ def get_attribute_filters(self):
attributes = [row.attribute for row in self.doc.filter_attributes]
- attribute_docs = [
- frappe.get_doc('Item Attribute', attribute) for attribute in attributes
- ]
- valid_attributes = []
+ if not attributes:
+ return []
- for attr_doc in attribute_docs:
- selected_attributes = []
- for attr in attr_doc.item_attribute_values:
- or_filters = []
- filters= [
- ["Item Variant Attribute", "attribute", "=", attr.parent],
- ["Item Variant Attribute", "attribute_value", "=", attr.attribute_value]
- ]
- if self.item_group:
- or_filters.extend([
- ["item_group", "=", self.item_group],
- ["Website Item Group", "item_group", "=", self.item_group]
- ])
+ result = frappe.db.sql(
+ """
+ select
+ distinct attribute, attribute_value
+ from
+ `tabItem Variant Attribute`
+ where
+ attribute in %(attributes)s
+ and attribute_value is not null
+ """,
+ {"attributes": attributes},
+ as_dict=1,
+ )
- if frappe.db.get_all("Item", filters, or_filters=or_filters, limit=1):
- selected_attributes.append(attr)
+ attribute_value_map = {}
+ for d in result:
+ attribute_value_map.setdefault(d.attribute, []).append(d.attribute_value)
- if selected_attributes:
- valid_attributes.append(
- _dict(
- item_attribute_values=selected_attributes,
- name=attr_doc.name
- )
- )
-
- return valid_attributes
+ out = []
+ for name, values in attribute_value_map.items():
+ out.append(frappe._dict(name=name, item_attribute_values=values))
+ return out
diff --git a/erpnext/shopping_cart/utils.py b/erpnext/shopping_cart/utils.py
index f412e61f062..5f0c7923814 100644
--- a/erpnext/shopping_cart/utils.py
+++ b/erpnext/shopping_cart/utils.py
@@ -1,8 +1,5 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-
import frappe
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import (
@@ -18,10 +15,19 @@ def show_cart_count():
return False
def set_cart_count(login_manager):
- role, parties = check_customer_or_supplier()
- if role == 'Supplier': return
+ # since this is run only on hooks login event
+ # make sure user is already a customer
+ # before trying to set cart count
+ user_is_customer = is_customer()
+ if not user_is_customer:
+ return
+
if show_cart_count():
from erpnext.shopping_cart.cart import set_cart_count
+
+ # set_cart_count will try to fetch existing cart quotation
+ # or create one if non existent (and create a customer too)
+ # cart count is calculated from this quotation's items
set_cart_count()
def clear_cart_count(login_manager):
@@ -32,13 +38,13 @@ def update_website_context(context):
cart_enabled = is_cart_enabled()
context["shopping_cart_enabled"] = cart_enabled
-def check_customer_or_supplier():
- if frappe.session.user:
+def is_customer():
+ if frappe.session.user and frappe.session.user != "Guest":
contact_name = frappe.get_value("Contact", {"email_id": frappe.session.user})
if contact_name:
contact = frappe.get_doc('Contact', contact_name)
for link in contact.links:
- if link.link_doctype in ('Customer', 'Supplier'):
- return link.link_doctype, link.link_name
+ if link.link_doctype == 'Customer':
+ return True
- return 'Customer', None
+ return False
diff --git a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
index 1e3d0d069a1..e560f4ad7de 100644
--- a/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
+++ b/erpnext/shopping_cart/web_template/hero_slider/hero_slider.html
@@ -1,7 +1,7 @@
{%- macro slide(image, title, subtitle, action, label, index, align="Left", theme="Dark") -%}
{%- set align_class = resolve_class({
'text-right': align == 'Right',
- 'text-centre': align == 'Center',
+ 'text-centre': align == 'Centre',
'text-left': align == 'Left',
}) -%}
@@ -15,7 +15,7 @@
{%- if title -%}
{{ title }} {%- endif -%}
- {%- if subtitle -%}
{{ subtitle }}
{%- endif -%}
+ {%- if subtitle -%}
{{ subtitle }}
{%- endif -%}
{%- if action -%}
{{ label }}
@@ -27,12 +27,14 @@
{%- endmacro -%}
-
+{%- set hero_slider_id = 'id-' + frappe.utils.generate_hash('HeroSlider', 12) -%}
+
+
{%- if show_indicators -%}
{%- for index in ['1', '2', '3', '4', '5'] -%}
{%- if values['slide_' + index + '_image'] -%}
-
+
{%- endif -%}
{%- endfor -%}
@@ -54,7 +56,7 @@
{%- endfor -%}
{%- if show_controls -%}
-
+
Previous
-
+
@@ -73,13 +75,12 @@
{%- endif -%}
-
-
-
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 79989307efc..0a663c2a188 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -1,8 +1,5 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
-from __future__ import unicode_literals
-
-import unittest
import frappe
from frappe.exceptions import ValidationError
@@ -11,9 +8,10 @@ from frappe.utils import cint, flt
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.stock.doctype.batch.batch import UnableToSelectBatchError, get_batch_no, get_batch_qty
from erpnext.stock.get_item_details import get_item_details
+from erpnext.tests.utils import ERPNextTestCase
-class TestBatch(unittest.TestCase):
+class TestBatch(ERPNextTestCase):
def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({
"doctype": "Batch",
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 5fbc2d8dee1..4be0415564d 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -14,51 +14,6 @@ class Bin(Document):
self.stock_uom = frappe.get_cached_value('Item', self.item_code, 'stock_uom')
self.set_projected_qty()
- def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
- '''Called from erpnext.stock.utils.update_bin'''
- self.update_qty(args)
-
- if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
- from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
-
- if not args.get("posting_date"):
- args["posting_date"] = nowdate()
-
- if args.get("is_cancelled") and via_landed_cost_voucher:
- return
-
- # Reposts only current voucher SL Entries
- # Updates valuation rate, stock value, stock queue for current transaction
- update_entries_after({
- "item_code": self.item_code,
- "warehouse": self.warehouse,
- "posting_date": args.get("posting_date"),
- "posting_time": args.get("posting_time"),
- "voucher_type": args.get("voucher_type"),
- "voucher_no": args.get("voucher_no"),
- "sle_id": args.name,
- "creation": args.creation
- }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
-
- # update qty in future ale and Validate negative qty
- update_qty_in_future_sle(args, allow_negative_stock)
-
-
- def update_qty(self, args):
- # update the stock values (for current quantities)
- if args.get("voucher_type")=="Stock Reconciliation":
- self.actual_qty = args.get("qty_after_transaction")
- else:
- self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty"))
-
- self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty"))
- self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))
- self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty"))
- self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty"))
-
- self.set_projected_qty()
- self.db_update()
-
def set_projected_qty(self):
self.projected_qty = (flt(self.actual_qty) + flt(self.ordered_qty)
+ flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
@@ -143,3 +98,67 @@ class Bin(Document):
def on_doctype_update():
frappe.db.add_index("Bin", ["item_code", "warehouse"])
+
+
+def update_stock(bin_name, args, allow_negative_stock=False, via_landed_cost_voucher=False):
+ '''Called from erpnext.stock.utils.update_bin'''
+ update_qty(bin_name, args)
+
+ if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
+ from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
+
+ if not args.get("posting_date"):
+ args["posting_date"] = nowdate()
+
+ if args.get("is_cancelled") and via_landed_cost_voucher:
+ return
+
+ # Reposts only current voucher SL Entries
+ # Updates valuation rate, stock value, stock queue for current transaction
+ update_entries_after({
+ "item_code": args.get('item_code'),
+ "warehouse": args.get('warehouse'),
+ "posting_date": args.get("posting_date"),
+ "posting_time": args.get("posting_time"),
+ "voucher_type": args.get("voucher_type"),
+ "voucher_no": args.get("voucher_no"),
+ "sle_id": args.get('name'),
+ "creation": args.get('creation')
+ }, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
+
+ # update qty in future sle and Validate negative qty
+ update_qty_in_future_sle(args, allow_negative_stock)
+
+def get_bin_details(bin_name):
+ return frappe.db.get_value('Bin', bin_name, ['actual_qty', 'ordered_qty',
+ 'reserved_qty', 'indented_qty', 'planned_qty', 'reserved_qty_for_production',
+ 'reserved_qty_for_sub_contract'], as_dict=1)
+
+def update_qty(bin_name, args):
+ bin_details = get_bin_details(bin_name)
+
+ # update the stock values (for current quantities)
+ if args.get("voucher_type")=="Stock Reconciliation":
+ actual_qty = args.get('qty_after_transaction')
+ else:
+ actual_qty = bin_details.actual_qty + flt(args.get("actual_qty"))
+
+ ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty"))
+ reserved_qty = flt(bin_details.reserved_qty) + flt(args.get("reserved_qty"))
+ indented_qty = flt(bin_details.indented_qty) + flt(args.get("indented_qty"))
+ planned_qty = flt(bin_details.planned_qty) + flt(args.get("planned_qty"))
+
+
+ # compute projected qty
+ projected_qty = (flt(actual_qty) + flt(ordered_qty)
+ + flt(indented_qty) + flt(planned_qty) - flt(reserved_qty)
+ - flt(bin_details.reserved_qty_for_production) - flt(bin_details.reserved_qty_for_sub_contract))
+
+ frappe.db.set_value('Bin', bin_name, {
+ 'actual_qty': actual_qty,
+ 'ordered_qty': ordered_qty,
+ 'reserved_qty': reserved_qty,
+ 'indented_qty': indented_qty,
+ 'planned_qty': planned_qty,
+ 'projected_qty': projected_qty
+ })
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index fdc8763baa6..ad1b3b43aee 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -395,8 +395,7 @@
"fieldtype": "Link",
"label": "Billing Address Name",
"options": "Address",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "tax_id",
@@ -1277,6 +1276,7 @@
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1308,7 +1308,7 @@
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-27 20:14:40.215231",
+ "modified": "2021-10-08 14:29:13.428984",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 5542cd00d4c..f75b52cec8e 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -185,7 +185,6 @@ class DeliveryNote(SellingController):
if not d['warehouse'] and frappe.db.get_value("Item", d['item_code'], "is_stock_item") == 1:
frappe.throw(_("Warehouse required for stock Item {0}").format(d["item_code"]))
-
def update_current_stock(self):
if self.get("_action") and self._action != "update_after_submit":
for d in self.get('items'):
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 7fda94b269d..f58b586ab20 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -5,7 +5,6 @@
from __future__ import unicode_literals
import json
-import unittest
import frappe
from frappe.utils import cstr, flt, nowdate, nowtime
@@ -37,9 +36,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
)
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
from erpnext.stock.stock_ledger import get_previous_sle
+from erpnext.tests.utils import ERPNextTestCase
-class TestDeliveryNote(unittest.TestCase):
+class TestDeliveryNote(ERPNextTestCase):
def test_over_billing_against_dn(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index b05090a237e..a96c29925e5 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -468,7 +468,7 @@
"width": "100px"
},
{
- "depends_on": "eval:parent.is_internal_customer",
+ "depends_on": "eval:parent.is_internal_customer || doc.target_warehouse",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
@@ -759,7 +759,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-23 01:04:08.588104",
+ "modified": "2021-10-05 12:12:44.018872",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
@@ -767,4 +767,4 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
index c9081c908f7..c6ff73e633b 100644
--- a/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/test_delivery_trip.py
@@ -14,11 +14,12 @@ from erpnext.stock.doctype.delivery_trip.delivery_trip import (
make_expense_claim,
notify_customers,
)
-from erpnext.tests.utils import create_test_contact_and_address
+from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address
-class TestDeliveryTrip(unittest.TestCase):
+class TestDeliveryTrip(ERPNextTestCase):
def setUp(self):
+ super().setUp()
driver = create_driver()
create_vehicle()
create_delivery_notification()
@@ -32,6 +33,7 @@ class TestDeliveryTrip(unittest.TestCase):
frappe.db.sql("delete from `tabVehicle`")
frappe.db.sql("delete from `tabEmail Template`")
frappe.db.sql("delete from `tabDelivery Trip`")
+ return super().tearDown()
def test_expense_claim_fields_are_fetched_properly(self):
expense_claim = make_expense_claim(self.delivery_trip.name)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index db5caf91645..4b314a00a42 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -17,7 +17,6 @@
"variant_of",
"item_name",
"item_group",
- "is_item_from_hub",
"stock_uom",
"column_break0",
"disabled",
@@ -134,12 +133,7 @@
"website_specifications",
"web_long_description",
"website_content",
- "total_projected_qty",
- "hub_publishing_sb",
- "publish_in_hub",
- "hub_category_to_publish",
- "hub_warehouse",
- "synced_with_hub"
+ "total_projected_qty"
],
"fields": [
{
@@ -202,14 +196,6 @@
"reqd": 1,
"search_index": 1
},
- {
- "default": "0",
- "depends_on": "eval:!doc.is_fixed_asset",
- "fieldname": "is_item_from_hub",
- "fieldtype": "Check",
- "label": "Is Item from Hub",
- "read_only": 1
- },
{
"fieldname": "stock_uom",
"fieldtype": "Link",
@@ -996,41 +982,6 @@
"print_hide": 1,
"read_only": 1
},
- {
- "collapsible": 1,
- "depends_on": "eval:(!doc.is_item_from_hub && !doc.is_fixed_asset)",
- "fieldname": "hub_publishing_sb",
- "fieldtype": "Section Break",
- "label": "Hub Publishing Details"
- },
- {
- "default": "0",
- "description": "Publish Item to hub.erpnext.com",
- "fieldname": "publish_in_hub",
- "fieldtype": "Check",
- "label": "Publish in Hub"
- },
- {
- "fieldname": "hub_category_to_publish",
- "fieldtype": "Data",
- "label": "Hub Category to Publish",
- "read_only": 1
- },
- {
- "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.",
- "fieldname": "hub_warehouse",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Hub Warehouse",
- "options": "Warehouse"
- },
- {
- "default": "0",
- "fieldname": "synced_with_hub",
- "fieldtype": "Check",
- "label": "Synced With Hub",
- "read_only": 1
- },
{
"depends_on": "eval:!doc.__islocal && !doc.is_fixed_asset",
"fieldname": "over_delivery_receipt_allowance",
@@ -1078,10 +1029,11 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2021-08-26 12:23:07.277077",
+ "modified": "2021-10-27 21:04:00.324786",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 50fdd3845d0..fa42c7d934b 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -4,6 +4,7 @@
import copy
import itertools
import json
+from typing import List
import frappe
from frappe import _
@@ -36,6 +37,7 @@ from erpnext.setup.doctype.item_group.item_group import (
get_parent_item_groups,
invalidate_cache_for,
)
+from erpnext.stock.doctype.item_default.item_default import ItemDefault
class DuplicateReorderRows(frappe.ValidationError):
@@ -121,7 +123,6 @@ class Item(WebsiteGenerator):
self.validate_barcode()
self.validate_warehouse_for_reorder()
self.update_bom_item_desc()
- self.synced_with_hub = 0
self.validate_has_variants()
self.validate_attributes_in_variants()
@@ -134,9 +135,9 @@ class Item(WebsiteGenerator):
self.validate_fixed_asset()
self.validate_retain_sample()
self.validate_uom_conversion_factor()
- self.validate_item_defaults()
self.validate_customer_provided_part()
self.update_defaults_from_item_group()
+ self.validate_item_defaults()
self.validate_auto_reorder_enabled_in_stock_settings()
self.cant_change()
self.update_show_in_website()
@@ -179,6 +180,8 @@ class Item(WebsiteGenerator):
"doctype": "Item Price",
"price_list": price_list,
"item_code": self.name,
+ "uom": self.stock_uom,
+ "brand": self.brand,
"currency": erpnext.get_default_currency(),
"price_list_rate": self.standard_rate
})
@@ -561,8 +564,12 @@ class Item(WebsiteGenerator):
_("Default BOM ({0}) must be active for this item or its template").format(bom_item))
def fill_customer_code(self):
- """ Append all the customer codes and insert into "customer_code" field of item table """
- self.customer_code = ','.join(d.ref_code for d in self.get("customer_items", []))
+ """
+ Append all the customer codes and insert into "customer_code" field of item table.
+ Used to search Item by customer code.
+ """
+ customer_codes = set(d.ref_code for d in self.get("customer_items", []))
+ self.customer_code = ','.join(customer_codes)
def check_item_tax(self):
"""Check whether Tax Rate is not entered twice for same Tax Type"""
@@ -628,9 +635,21 @@ class Item(WebsiteGenerator):
_("An Item Group exists with same name, please change the item name or rename the item group"))
def update_item_price(self):
- frappe.db.sql("""update `tabItem Price` set item_name=%s,
- item_description=%s, brand=%s where item_code=%s""",
- (self.item_name, self.description, self.brand, self.name))
+ frappe.db.sql("""
+ UPDATE `tabItem Price`
+ SET
+ item_name=%(item_name)s,
+ item_description=%(item_description)s,
+ brand=%(brand)s
+ WHERE item_code=%(item_code)s
+ """,
+ dict(
+ item_name=self.item_name,
+ item_description=self.description,
+ brand=self.brand,
+ item_code=self.name
+ )
+ )
def on_trash(self):
super(Item, self).on_trash()
@@ -657,6 +676,8 @@ class Item(WebsiteGenerator):
def after_rename(self, old_name, new_name, merge):
if merge:
self.validate_duplicate_item_in_stock_reconciliation(old_name, new_name)
+ frappe.msgprint(_("It can take upto few hours for accurate stock values to be visible after merging items."),
+ indicator="orange", title="Note")
if self.route:
invalidate_cache_for_item(self)
@@ -782,35 +803,39 @@ class Item(WebsiteGenerator):
if len(companies) != len(self.item_defaults):
frappe.throw(_("Cannot set multiple Item Defaults for a company."))
+ validate_item_default_company_links(self.item_defaults)
+
+
def update_defaults_from_item_group(self):
"""Get defaults from Item Group"""
- if self.item_group and not self.item_defaults:
- item_defaults = frappe.db.get_values("Item Default", {"parent": self.item_group},
- ['company', 'default_warehouse','default_price_list','buying_cost_center','default_supplier',
- 'expense_account','selling_cost_center','income_account'], as_dict = 1)
- if item_defaults:
- for item in item_defaults:
- self.append('item_defaults', {
- 'company': item.company,
- 'default_warehouse': item.default_warehouse,
- 'default_price_list': item.default_price_list,
- 'buying_cost_center': item.buying_cost_center,
- 'default_supplier': item.default_supplier,
- 'expense_account': item.expense_account,
- 'selling_cost_center': item.selling_cost_center,
- 'income_account': item.income_account
- })
- else:
- warehouse = ''
- defaults = frappe.defaults.get_defaults() or {}
+ if self.item_defaults or not self.item_group:
+ return
- # To check default warehouse is belong to the default company
- if defaults.get("default_warehouse") and defaults.company and frappe.db.exists("Warehouse",
- {'name': defaults.default_warehouse, 'company': defaults.company}):
- self.append("item_defaults", {
- "company": defaults.get("company"),
- "default_warehouse": defaults.default_warehouse
- })
+ item_defaults = frappe.db.get_values("Item Default", {"parent": self.item_group},
+ ['company', 'default_warehouse','default_price_list','buying_cost_center','default_supplier',
+ 'expense_account','selling_cost_center','income_account'], as_dict = 1)
+ if item_defaults:
+ for item in item_defaults:
+ self.append('item_defaults', {
+ 'company': item.company,
+ 'default_warehouse': item.default_warehouse,
+ 'default_price_list': item.default_price_list,
+ 'buying_cost_center': item.buying_cost_center,
+ 'default_supplier': item.default_supplier,
+ 'expense_account': item.expense_account,
+ 'selling_cost_center': item.selling_cost_center,
+ 'income_account': item.income_account
+ })
+ else:
+ defaults = frappe.defaults.get_defaults() or {}
+
+ # To check default warehouse is belong to the default company
+ if defaults.get("default_warehouse") and defaults.company and frappe.db.exists("Warehouse",
+ {'name': defaults.default_warehouse, 'company': defaults.company}):
+ self.append("item_defaults", {
+ "company": defaults.get("company"),
+ "default_warehouse": defaults.default_warehouse
+ })
def update_variants(self):
if self.flags.dont_update_variants or \
@@ -1328,3 +1353,25 @@ def on_doctype_update():
@erpnext.allow_regional
def set_item_tax_from_hsn_code(item):
pass
+
+
+def validate_item_default_company_links(item_defaults: List[ItemDefault]) -> None:
+ for item_default in item_defaults:
+ for doctype, field in [
+ ['Warehouse', 'default_warehouse'],
+ ['Cost Center', 'buying_cost_center'],
+ ['Cost Center', 'selling_cost_center'],
+ ['Account', 'expense_account'],
+ ['Account', 'income_account']
+ ]:
+ if item_default.get(field):
+ company = frappe.db.get_value(doctype, item_default.get(field), 'company', cache=True)
+ if company and company != item_default.company:
+ frappe.throw(_("Row #{}: {} {} doesn't belong to Company {}. Please select valid {}.")
+ .format(
+ item_default.idx,
+ doctype,
+ frappe.bold(item_default.get(field)),
+ frappe.bold(item_default.company),
+ frappe.bold(frappe.unscrub(field))
+ ), title=_("Invalid Item Defaults"))
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 0ed27610200..9198272513b 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -4,7 +4,6 @@
from __future__ import unicode_literals
import json
-import unittest
import frappe
from frappe.test_runner import make_test_objects
@@ -25,7 +24,7 @@ from erpnext.stock.doctype.item.item import (
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.get_item_details import get_item_details
-from erpnext.tests.utils import change_settings
+from erpnext.tests.utils import ERPNextTestCase, change_settings
test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
@@ -53,8 +52,9 @@ def make_item(item_code, properties=None):
return item
-class TestItem(unittest.TestCase):
+class TestItem(ERPNextTestCase):
def setUp(self):
+ super().setUp()
frappe.flags.attribute_values = None
def get_item(self, idx):
@@ -232,6 +232,23 @@ class TestItem(unittest.TestCase):
for key, value in purchase_item_check.items():
self.assertEqual(value, purchase_item_details.get(key))
+ def test_item_default_validations(self):
+
+ with self.assertRaises(frappe.ValidationError) as ve:
+ make_item("Bad Item defaults", {
+ "item_group": "_Test Item Group",
+ "item_defaults": [{
+ "company": "_Test Company 1",
+ "default_warehouse": "_Test Warehouse - _TC",
+ "expense_account": "Stock In Hand - _TC",
+ "buying_cost_center": "_Test Cost Center - _TC",
+ "selling_cost_center": "_Test Cost Center - _TC",
+ }]
+ })
+
+ self.assertTrue("belong to company" in str(ve.exception).lower(),
+ msg="Mismatching company entities in item defaults should not be allowed.")
+
def test_item_attribute_change_after_variant(self):
frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1)
diff --git a/erpnext/stock/doctype/item_alternative/item_alternative.py b/erpnext/stock/doctype/item_alternative/item_alternative.py
index 6080fb4a5fa..6f2a389b707 100644
--- a/erpnext/stock/doctype/item_alternative/item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/item_alternative.py
@@ -25,19 +25,29 @@ class ItemAlternative(Document):
frappe.throw(_("Alternative item must not be same as item code"))
item_meta = frappe.get_meta("Item")
- fields = ["is_stock_item", "include_item_in_manufacturing","has_serial_no","has_batch_no"]
- item_data = frappe.db.get_values("Item", self.item_code, fields, as_dict=1)
- alternative_item_data = frappe.db.get_values("Item", self.alternative_item_code, fields, as_dict=1)
+ fields = ["is_stock_item", "include_item_in_manufacturing","has_serial_no", "has_batch_no", "allow_alternative_item"]
+ item_data = frappe.db.get_value("Item", self.item_code, fields, as_dict=1)
+ alternative_item_data = frappe.db.get_value("Item", self.alternative_item_code, fields, as_dict=1)
for field in fields:
- if item_data[0].get(field) != alternative_item_data[0].get(field):
+ if item_data.get(field) != alternative_item_data.get(field):
raise_exception, alert = [1, False] if field == "is_stock_item" else [0, True]
frappe.msgprint(_("The value of {0} differs between Items {1} and {2}") \
.format(frappe.bold(item_meta.get_label(field)),
frappe.bold(self.alternative_item_code),
frappe.bold(self.item_code)),
- alert=alert, raise_exception=raise_exception)
+ alert=alert, raise_exception=raise_exception, indicator="Orange")
+
+ alternate_item_check_msg = _("Allow Alternative Item must be checked on Item {}")
+
+ if not item_data.allow_alternative_item:
+ frappe.throw(alternate_item_check_msg.format(self.item_code))
+ if self.two_way and not alternative_item_data.allow_alternative_item:
+ frappe.throw(alternate_item_check_msg.format(self.item_code))
+
+
+
def validate_duplicate(self):
if frappe.db.get_value("Item Alternative", {'item_code': self.item_code,
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
index 2be8ef740a4..af6cc472e34 100644
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
@@ -4,7 +4,6 @@
from __future__ import unicode_literals
import json
-import unittest
import frappe
from frappe.utils import flt
@@ -21,10 +20,12 @@ from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
+from erpnext.tests.utils import ERPNextTestCase
-class TestItemAlternative(unittest.TestCase):
+class TestItemAlternative(ERPNextTestCase):
def setUp(self):
+ super().setUp()
make_items()
def test_alternative_item_for_subcontract_rm(self):
diff --git a/erpnext/stock/doctype/item_attribute/test_item_attribute.py b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
index fc809f443e6..2cd711bbb19 100644
--- a/erpnext/stock/doctype/item_attribute/test_item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/test_item_attribute.py
@@ -3,17 +3,17 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
test_records = frappe.get_test_records('Item Attribute')
from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError
+from erpnext.tests.utils import ERPNextTestCase
-class TestItemAttribute(unittest.TestCase):
+class TestItemAttribute(ERPNextTestCase):
def setUp(self):
+ super().setUp()
if frappe.db.exists("Item Attribute", "_Test_Length"):
frappe.delete_doc("Item Attribute", "_Test_Length")
diff --git a/erpnext/stock/doctype/item_price/test_item_price.py b/erpnext/stock/doctype/item_price/test_item_price.py
index 5ed80921660..3a51fbbe17e 100644
--- a/erpnext/stock/doctype/item_price/test_item_price.py
+++ b/erpnext/stock/doctype/item_price/test_item_price.py
@@ -3,17 +3,17 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.test_runner import make_test_records_for_doctype
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
from erpnext.stock.get_item_details import get_price_list_rate_for, process_args
+from erpnext.tests.utils import ERPNextTestCase
-class TestItemPrice(unittest.TestCase):
+class TestItemPrice(ERPNextTestCase):
def setUp(self):
+ super().setUp()
frappe.db.sql("delete from `tabItem Price`")
make_test_records_for_doctype("Item Price", force=True)
diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
index e8fb34732fc..488920aadbc 100644
--- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
+++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js
@@ -2,19 +2,32 @@
// For license information, please see license.txt
frappe.ui.form.on('Item Variant Settings', {
- setup: function(frm) {
+ refresh: function(frm) {
const allow_fields = [];
- const exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website",
- "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"];
+
+ const existing_fields = frm.doc.fields.map(row => row.field_name);
+ const exclude_fields = [...existing_fields, "naming_series", "item_code", "item_name",
+ "show_in_website", "show_variant_in_website", "standard_rate", "opening_stock", "image",
+ "variant_of", "valuation_rate", "barcodes", "website_image", "thumbnail",
+ "website_specifiations", "web_long_description", "has_variants", "attributes"];
+
+ const exclude_field_types = ['HTML', 'Section Break', 'Column Break', 'Button', 'Read Only'];
frappe.model.with_doctype('Item', () => {
frappe.get_meta('Item').fields.forEach(d => {
- if(!in_list(['HTML', 'Section Break', 'Column Break', 'Button', 'Read Only'], d.fieldtype)
+ if (!in_list(exclude_field_types, d.fieldtype)
&& !d.no_copy && !in_list(exclude_fields, d.fieldname)) {
allow_fields.push(d.fieldname);
}
});
+ if (allow_fields.length == 0) {
+ allow_fields.push({
+ label: __("No additional fields available"),
+ value: "",
+ });
+ }
+
frm.fields_dict.fields.grid.update_docfield_property(
'field_name', 'options', allow_fields
);
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 58a72f72dd1..339eaaaf7a5 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -4,8 +4,6 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.utils import flt
@@ -16,9 +14,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
get_gl_entries,
make_purchase_receipt,
)
+from erpnext.tests.utils import ERPNextTestCase
-class TestLandedCostVoucher(unittest.TestCase):
+class TestLandedCostVoucher(ERPNextTestCase):
def test_landed_cost_voucher(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 9eb47216266..ec01cae2567 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -6,10 +6,13 @@
from __future__ import unicode_literals
+import json
+
import frappe
from frappe import _, msgprint
from frappe.model.mapper import get_mapped_doc
from frappe.utils import cstr, flt, get_link_to_form, getdate, new_line_sep, nowdate
+from six import string_types
from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.controllers.buying_controller import BuyingController
@@ -269,7 +272,11 @@ def update_status(name, status):
material_request.update_status(status)
@frappe.whitelist()
-def make_purchase_order(source_name, target_doc=None):
+def make_purchase_order(source_name, target_doc=None, args=None):
+ if args is None:
+ args = {}
+ if isinstance(args, string_types):
+ args = json.loads(args)
def postprocess(source, target_doc):
if frappe.flags.args and frappe.flags.args.default_supplier:
@@ -284,9 +291,12 @@ def make_purchase_order(source_name, target_doc=None):
set_missing_values(source, target_doc)
def select_item(d):
- return d.ordered_qty < d.stock_qty
+ filtered_items = args.get('filtered_children', [])
+ child_filter = d.name in filtered_items if filtered_items else True
- doclist = get_mapped_doc("Material Request", source_name, {
+ return d.ordered_qty < d.stock_qty and child_filter
+
+ doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": {
"doctype": "Purchase Order",
"validation": {
@@ -313,7 +323,7 @@ def make_purchase_order(source_name, target_doc=None):
@frappe.whitelist()
def make_request_for_quotation(source_name, target_doc=None):
- doclist = get_mapped_doc("Material Request", source_name, {
+ doclist = get_mapped_doc("Material Request", source_name, {
"Material Request": {
"doctype": "Request for Quotation",
"validation": {
@@ -492,7 +502,8 @@ def make_stock_entry(source_name, target_doc=None):
"field_map": {
"name": "material_request_item",
"parent": "material_request",
- "uom": "stock_uom"
+ "uom": "stock_uom",
+ "job_card_item": "job_card_item"
},
"postprocess": update_item,
"condition": lambda doc: doc.ordered_qty < doc.stock_qty
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 5c2ac2584f7..f66a228e35e 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -6,8 +6,6 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.utils import flt, today
@@ -18,9 +16,10 @@ from erpnext.stock.doctype.material_request.material_request import (
make_supplier_quotation,
raise_work_orders,
)
+from erpnext.tests.utils import ERPNextTestCase
-class TestMaterialRequest(unittest.TestCase):
+class TestMaterialRequest(ERPNextTestCase):
def test_make_purchase_order(self):
mr = frappe.copy_doc(test_records[0]).insert()
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index 25bbbbd4b3e..2bad42a0ebb 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -52,6 +52,7 @@
"sales_order_item",
"production_plan",
"material_request_plan_item",
+ "job_card_item",
"col_break4",
"expense_account",
"section_break_46",
@@ -444,16 +445,25 @@
{
"fieldname": "qty_info_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "job_card_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "no_copy": 1,
+ "print_hide": 1,
+ "label": "Job Card Item"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-10-02 11:44:36.553064",
+ "modified": "2021-11-03 14:40:24.409826",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request Item",
+ "naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
diff --git a/erpnext/stock/doctype/packing_slip/test_packing_slip.py b/erpnext/stock/doctype/packing_slip/test_packing_slip.py
index 193adfcf1cb..c70cba67f2b 100644
--- a/erpnext/stock/doctype/packing_slip/test_packing_slip.py
+++ b/erpnext/stock/doctype/packing_slip/test_packing_slip.py
@@ -6,6 +6,8 @@ from __future__ import unicode_literals
import unittest
# test_records = frappe.get_test_records('Packing Slip')
+from erpnext.tests.utils import ERPNextTestCase
+
class TestPackingSlip(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json
index 21467935370..c604c711ef5 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.json
+++ b/erpnext/stock/doctype/pick_list/pick_list.json
@@ -18,7 +18,9 @@
"get_item_locations",
"section_break_6",
"locations",
- "amended_from"
+ "amended_from",
+ "print_settings_section",
+ "group_same_items"
],
"fields": [
{
@@ -110,14 +112,28 @@
"options": "STO-PICK-.YYYY.-",
"reqd": 1,
"set_only_once": 1
+ },
+ {
+ "fieldname": "print_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Print Settings"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "group_same_items",
+ "fieldtype": "Check",
+ "label": "Group Same Items",
+ "print_hide": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-03-17 11:38:41.932875",
+ "modified": "2021-10-05 15:08:40.369957",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@@ -184,4 +200,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index dffbe80fa39..4c02f3db43b 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -2,10 +2,8 @@
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-
import json
-from collections import OrderedDict
+from collections import OrderedDict, defaultdict
import frappe
from frappe import _
@@ -121,6 +119,34 @@ class PickList(Document):
and (self.for_qty is None or self.for_qty == 0):
frappe.throw(_("Qty of Finished Goods Item should be greater than 0."))
+ def before_print(self, settings=None):
+ if self.get("group_same_items"):
+ self.group_similar_items()
+
+ def group_similar_items(self):
+ group_item_qty = defaultdict(float)
+ group_picked_qty = defaultdict(float)
+
+ for item in self.locations:
+ group_item_qty[(item.item_code, item.warehouse)] += item.qty
+ group_picked_qty[(item.item_code, item.warehouse)] += item.picked_qty
+
+ duplicate_list = []
+ for item in self.locations:
+ if (item.item_code, item.warehouse) in group_item_qty:
+ item.qty = group_item_qty[(item.item_code, item.warehouse)]
+ item.picked_qty = group_picked_qty[(item.item_code, item.warehouse)]
+ item.stock_qty = group_item_qty[(item.item_code, item.warehouse)]
+ del group_item_qty[(item.item_code, item.warehouse)]
+ else:
+ duplicate_list.append(item)
+
+ for item in duplicate_list:
+ self.remove(item)
+
+ for idx, item in enumerate(self.locations, start=1):
+ item.idx = idx
+
def validate_item_locations(pick_list):
if not pick_list.locations:
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index aa710ad0e97..58b46e1eefc 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -3,9 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import unittest
-
import frappe
+from frappe import _dict
test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
@@ -15,9 +14,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
EmptyStockReconciliationItemsError,
)
+from erpnext.tests.utils import ERPNextTestCase
-class TestPickList(unittest.TestCase):
+class TestPickList(ERPNextTestCase):
def test_pick_list_picks_warehouse_for_each_item(self):
try:
@@ -357,6 +357,39 @@ class TestPickList(unittest.TestCase):
sales_order.cancel()
purchase_receipt.cancel()
+ def test_pick_list_grouping_before_print(self):
+ def _compare_dicts(a, b):
+ "compare dicts but ignore missing keys in `a`"
+ for key, value in a.items():
+ self.assertEqual(b.get(key), value, msg=f"{key} doesn't match")
+
+ # nothing should be grouped
+ pl = frappe.get_doc(doctype="Pick List", group_same_items=True, locations=[
+ _dict(item_code="A", warehouse="X", qty=1, picked_qty=2),
+ _dict(item_code="B", warehouse="X", qty=1, picked_qty=2),
+ _dict(item_code="A", warehouse="Y", qty=1, picked_qty=2),
+ _dict(item_code="B", warehouse="Y", qty=1, picked_qty=2),
+ ])
+ pl.before_print()
+ self.assertEqual(len(pl.locations), 4)
+
+ # grouping should halve the number of items
+ pl = frappe.get_doc(doctype="Pick List", group_same_items=True, locations=[
+ _dict(item_code="A", warehouse="X", qty=5, picked_qty=1),
+ _dict(item_code="B", warehouse="Y", qty=4, picked_qty=2),
+ _dict(item_code="A", warehouse="X", qty=3, picked_qty=2),
+ _dict(item_code="B", warehouse="Y", qty=2, picked_qty=2),
+ ])
+ pl.before_print()
+ self.assertEqual(len(pl.locations), 2)
+
+ expected_items = [
+ _dict(item_code="A", warehouse="X", qty=8, picked_qty=3),
+ _dict(item_code="B", warehouse="Y", qty=6, picked_qty=4),
+ ]
+ for expected_item, created_item in zip(expected_items, pl.locations):
+ _compare_dicts(expected_item, created_item)
+
# def test_pick_list_skips_items_in_expired_batch(self):
# pass
diff --git a/erpnext/stock/doctype/pick_list_item/pick_list_item.json b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
index 8665986004d..805286ddcc0 100644
--- a/erpnext/stock/doctype/pick_list_item/pick_list_item.json
+++ b/erpnext/stock/doctype/pick_list_item/pick_list_item.json
@@ -36,7 +36,8 @@
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Qty"
+ "label": "Qty",
+ "reqd": 1
},
{
"fieldname": "picked_qty",
@@ -180,7 +181,7 @@
],
"istable": 1,
"links": [],
- "modified": "2020-06-24 17:18:57.357120",
+ "modified": "2021-09-28 12:02:16.923056",
"modified_by": "Administrator",
"module": "Stock",
"name": "Pick List Item",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 1a597343c0a..112ddedac29 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1140,6 +1140,7 @@
"fetch_from": "supplier.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
+ "ignore_user_permissions": 1,
"label": "Represents Company",
"options": "Company",
"read_only": 1
@@ -1149,7 +1150,7 @@
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:16:40.849885",
+ "modified": "2021-09-28 13:11:10.181328",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 07a568db869..47c8df9a2c9 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -842,7 +842,8 @@ def make_stock_entry(source_name,target_doc=None):
"doctype": "Stock Entry Detail",
"field_map": {
"warehouse": "s_warehouse",
- "parent": "reference_purchase_receipt"
+ "parent": "reference_purchase_receipt",
+ "batch_no": "batch_no"
},
},
}, target_doc, set_missing_values)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 044856cca95..de177444285 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -17,9 +17,10 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchas
from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
+from erpnext.tests.utils import ERPNextTestCase
-class TestPurchaseReceipt(unittest.TestCase):
+class TestPurchaseReceipt(ERPNextTestCase):
def setUp(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
index 0aa7610575e..c25bca94dbb 100644
--- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -3,8 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import unittest
-
import frappe
from erpnext.stock.doctype.batch.test_batch import make_new_batch
@@ -13,9 +11,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.get_item_details import get_conversion_factor
+from erpnext.tests.utils import ERPNextTestCase
-class TestPutawayRule(unittest.TestCase):
+class TestPutawayRule(ERPNextTestCase):
def setUp(self):
if not frappe.db.exists("Item", "_Rice"):
make_item("_Rice", {
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index f5d076a077a..308c62875d5 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -1,8 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
-import unittest
-
import frappe
from frappe.utils import nowdate
@@ -15,12 +13,14 @@ from erpnext.controllers.stock_controller import (
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.tests.utils import ERPNextTestCase
# test_records = frappe.get_test_records('Quality Inspection')
-class TestQualityInspection(unittest.TestCase):
+class TestQualityInspection(ERPNextTestCase):
def setUp(self):
+ super().setUp()
create_item("_Test Item with QA")
frappe.db.set_value(
"Item", "_Test Item with QA", "inspection_required_before_delivery", 1
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 62b3a6adf7f..d86e52fa641 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -7,7 +7,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, now, today
+from frappe.utils import cint, get_link_to_form, get_weekday, now, nowtime, today
from frappe.utils.user import get_users_with_role
from rq.timeouts import JobTimeoutException
@@ -126,6 +126,9 @@ def notify_error_to_stock_managers(doc, traceback):
frappe.sendmail(recipients=recipients, subject=subject, message=message)
def repost_entries():
+ if not in_configured_timeslot():
+ return
+
riv_entries = get_repost_item_valuation_entries()
for row in riv_entries:
@@ -144,3 +147,26 @@ def get_repost_item_valuation_entries():
WHERE status in ('Queued', 'In Progress') and creation <= %s and docstatus = 1
ORDER BY timestamp(posting_date, posting_time) asc, creation asc
""", now(), as_dict=1)
+
+
+def in_configured_timeslot(repost_settings=None, current_time=None):
+ """Check if current time is in configured timeslot for reposting."""
+
+ if repost_settings is None:
+ repost_settings = frappe.get_cached_doc("Stock Reposting Settings")
+
+ if not repost_settings.limit_reposting_timeslot:
+ return True
+
+ if get_weekday() == repost_settings.limits_dont_apply_on:
+ return True
+
+ start_time = repost_settings.start_time
+ end_time = repost_settings.end_time
+
+ now_time = current_time or nowtime()
+
+ if start_time < end_time:
+ return end_time >= now_time >= start_time
+ else:
+ return now_time >= start_time or now_time <= end_time
diff --git a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
index c70a9ec7a8b..c086f938b5d 100644
--- a/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/test_repost_item_valuation.py
@@ -1,11 +1,72 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
-from __future__ import unicode_literals
-# import frappe
import unittest
+import frappe
+
+from erpnext.stock.doctype.repost_item_valuation.repost_item_valuation import (
+ in_configured_timeslot,
+)
+
class TestRepostItemValuation(unittest.TestCase):
- pass
+ def test_repost_time_slot(self):
+ repost_settings = frappe.get_doc("Stock Reposting Settings")
+
+ positive_cases = [
+ {"limit_reposting_timeslot": 0},
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "18:00:00",
+ "end_time": "09:00:00",
+ "current_time": "20:00:00",
+ },
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "09:00:00",
+ "end_time": "18:00:00",
+ "current_time": "12:00:00",
+ },
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "23:00:00",
+ "end_time": "09:00:00",
+ "current_time": "2:00:00",
+ },
+ ]
+
+ for case in positive_cases:
+ repost_settings.update(case)
+ self.assertTrue(
+ in_configured_timeslot(repost_settings, case.get("current_time")),
+ msg=f"Exepcted true from : {case}",
+ )
+
+ negative_cases = [
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "18:00:00",
+ "end_time": "09:00:00",
+ "current_time": "09:01:00",
+ },
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "09:00:00",
+ "end_time": "18:00:00",
+ "current_time": "19:00:00",
+ },
+ {
+ "limit_reposting_timeslot": 1,
+ "start_time": "23:00:00",
+ "end_time": "09:00:00",
+ "current_time": "22:00:00",
+ },
+ ]
+
+ for case in negative_cases:
+ repost_settings.update(case)
+ self.assertFalse(
+ in_configured_timeslot(repost_settings, case.get("current_time")),
+ msg=f"Exepcted false from : {case}",
+ )
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 82d8aaed5b3..a9254fb9ecf 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -611,7 +611,9 @@ def get_pos_reserved_serial_nos(filters):
return reserved_sr_nos
-def fetch_serial_numbers(filters, qty, do_not_include=[]):
+def fetch_serial_numbers(filters, qty, do_not_include=None):
+ if do_not_include is None:
+ do_not_include = []
batch_join_selection = ""
batch_no_condition = ""
batch_nos = filters.get("batch_no")
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index 818c163c681..570f22e6af3 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -6,8 +6,6 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
@@ -20,9 +18,10 @@ test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No')
from erpnext.stock.doctype.serial_no.serial_no import *
+from erpnext.tests.utils import ERPNextTestCase
-class TestSerialNo(unittest.TestCase):
+class TestSerialNo(ERPNextTestCase):
def test_cannot_create_direct(self):
frappe.delete_doc_if_exists("Serial No", "_TCSER0001")
@@ -185,14 +184,14 @@ class TestSerialNo(unittest.TestCase):
se = frappe.copy_doc(test_records[0])
se.get("items")[0].item_code = item_code
- se.get("items")[0].qty = 3
- se.get("items")[0].serial_no = " _TS1, _TS2 , _TS3 "
- se.get("items")[0].transfer_qty = 3
+ se.get("items")[0].qty = 4
+ se.get("items")[0].serial_no = " _TS1, _TS2 , _TS3 , _TS4 - 2021"
+ se.get("items")[0].transfer_qty = 4
se.set_stock_entry_type()
se.insert()
se.submit()
- self.assertEqual(se.get("items")[0].serial_no, "_TS1\n_TS2\n_TS3")
+ self.assertEqual(se.get("items")[0].serial_no, "_TS1\n_TS2\n_TS3\n_TS4 - 2021")
frappe.db.rollback()
diff --git a/erpnext/stock/doctype/shipment/test_shipment.py b/erpnext/stock/doctype/shipment/test_shipment.py
index 9914cf80158..dcd0b7c17c7 100644
--- a/erpnext/stock/doctype/shipment/test_shipment.py
+++ b/erpnext/stock/doctype/shipment/test_shipment.py
@@ -3,15 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import unittest
from datetime import date, timedelta
import frappe
from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
+from erpnext.tests.utils import ERPNextTestCase
-class TestShipment(unittest.TestCase):
+class TestShipment(ERPNextTestCase):
def test_shipment_from_delivery_note(self):
delivery_note = create_test_delivery_note()
delivery_note.submit()
@@ -47,7 +47,6 @@ def create_test_delivery_note():
}
)
delivery_note.insert()
- frappe.db.commit()
return delivery_note
@@ -91,7 +90,6 @@ def create_test_shipment(delivery_notes = None):
}
)
shipment.insert()
- frappe.db.commit()
return shipment
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index c819d49f509..c4b8131305e 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -88,7 +88,11 @@ frappe.ui.form.on('Stock Entry', {
}
}
- filters["warehouse"] = item.s_warehouse || item.t_warehouse;
+ // User could want to select a manually created empty batch (no warehouse)
+ // or a pre-existing batch
+ if (frm.doc.purpose != "Material Receipt") {
+ filters["warehouse"] = item.s_warehouse || item.t_warehouse;
+ }
return {
query : "erpnext.controllers.queries.get_batch_no",
@@ -323,6 +327,12 @@ frappe.ui.form.on('Stock Entry', {
attach_bom_items(frm.doc.bom_no)
},
+ before_save: function(frm) {
+ frm.doc.items.forEach((item) => {
+ item.uom = item.uom || item.stock_uom;
+ })
+ },
+
stock_entry_type: function(frm){
frm.remove_custom_button('Bill of Materials', "Get Items From");
frm.events.show_bom_custom_button(frm);
@@ -548,44 +558,7 @@ frappe.ui.form.on('Stock Entry', {
calculate_basic_amount: function(frm, item) {
item.basic_amount = flt(flt(item.transfer_qty) * flt(item.basic_rate),
precision("basic_amount", item));
-
- frm.events.calculate_amount(frm);
- },
-
- calculate_amount: function(frm) {
frm.events.calculate_total_additional_costs(frm);
- let total_basic_amount = 0;
- if (in_list(["Repack", "Manufacture"], frm.doc.purpose)) {
- total_basic_amount = frappe.utils.sum(
- (frm.doc.items || []).map(function(i) {
- return i.is_finished_item ? flt(i.basic_amount) : 0;
- })
- );
- } else {
- total_basic_amount = frappe.utils.sum(
- (frm.doc.items || []).map(function(i) {
- return i.t_warehouse ? flt(i.basic_amount) : 0;
- })
- );
- }
- for (let i in frm.doc.items) {
- let item = frm.doc.items[i];
-
- if (((in_list(["Repack", "Manufacture"], frm.doc.purpose) && item.is_finished_item) || item.t_warehouse) && total_basic_amount) {
- item.additional_cost = (flt(item.basic_amount) / total_basic_amount) * frm.doc.total_additional_costs;
- } else {
- item.additional_cost = 0;
- }
-
- item.amount = flt(item.basic_amount + flt(item.additional_cost), precision("amount", item));
-
- if (flt(item.transfer_qty)) {
- item.valuation_rate = flt(flt(item.basic_rate) + (flt(item.additional_cost) / flt(item.transfer_qty)),
- precision("valuation_rate", item));
- }
- }
-
- refresh_field('items');
},
calculate_total_additional_costs: function(frm) {
@@ -781,11 +754,6 @@ frappe.ui.form.on('Landed Cost Taxes and Charges', {
amount: function(frm, cdt, cdn) {
frm.events.set_base_amount(frm, cdt, cdn);
- // Adding this check because same table in used in LCV
- // This causes an error if you try to post an LCV immediately after a Stock Entry
- if (frm.doc.doctype == 'Stock Entry') {
- frm.events.calculate_amount(frm);
- }
},
expense_account: function(frm, cdt, cdn) {
@@ -1100,4 +1068,4 @@ function check_should_not_attach_bom_items(bom_no) {
);
}
-$.extend(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
+extend_cscript(cur_frm.cscript, new erpnext.stock.StockEntry({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 41ca8300a8e..bd7d22bcbc0 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import json
+from collections import defaultdict
import frappe
from frappe import _
@@ -554,22 +555,27 @@ class StockEntry(StockController):
def distribute_additional_costs(self):
# If no incoming items, set additional costs blank
- if not any([d.item_code for d in self.items if d.t_warehouse]):
+ if not any(d.item_code for d in self.items if d.t_warehouse):
self.additional_costs = []
- self.total_additional_costs = sum([flt(t.base_amount) for t in self.get("additional_costs")])
+ self.total_additional_costs = sum(flt(t.base_amount) for t in self.get("additional_costs"))
if self.purpose in ("Repack", "Manufacture"):
- incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.is_finished_item])
+ incoming_items_cost = sum(flt(t.basic_amount) for t in self.get("items") if t.is_finished_item)
else:
- incoming_items_cost = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+ incoming_items_cost = sum(flt(t.basic_amount) for t in self.get("items") if t.t_warehouse)
- if incoming_items_cost:
- for d in self.get("items"):
- if (self.purpose in ("Repack", "Manufacture") and d.is_finished_item) or d.t_warehouse:
- d.additional_cost = (flt(d.basic_amount) / incoming_items_cost) * self.total_additional_costs
- else:
- d.additional_cost = 0
+ if not incoming_items_cost:
+ return
+
+ for d in self.get("items"):
+ if self.purpose in ("Repack", "Manufacture") and not d.is_finished_item:
+ d.additional_cost = 0
+ continue
+ elif not d.t_warehouse:
+ d.additional_cost = 0
+ continue
+ d.additional_cost = (flt(d.basic_amount) / incoming_items_cost) * self.total_additional_costs
def update_valuation_rate(self):
for d in self.get("items"):
@@ -684,7 +690,7 @@ class StockEntry(StockController):
def validate_bom(self):
for d in self.get('items'):
- if d.bom_no and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
+ if d.bom_no and d.is_finished_item:
item_code = d.original_item or d.item_code
validate_bom_no(item_code, d.bom_no)
@@ -804,7 +810,11 @@ class StockEntry(StockController):
def get_gl_entries(self, warehouse_account):
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
- total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+ if self.purpose in ("Repack", "Manufacture"):
+ total_basic_amount = sum(flt(t.basic_amount) for t in self.get("items") if t.is_finished_item)
+ else:
+ total_basic_amount = sum(flt(t.basic_amount) for t in self.get("items") if t.t_warehouse)
+
divide_based_on = total_basic_amount
if self.get("additional_costs") and not total_basic_amount:
@@ -815,20 +825,24 @@ class StockEntry(StockController):
for t in self.get("additional_costs"):
for d in self.get("items"):
- if d.t_warehouse:
- item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
- item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, {
- "amount": 0.0,
- "base_amount": 0.0
- })
+ if self.purpose in ("Repack", "Manufacture") and not d.is_finished_item:
+ continue
+ elif not d.t_warehouse:
+ continue
- multiply_based_on = d.basic_amount if total_basic_amount else d.qty
+ item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
+ item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, {
+ "amount": 0.0,
+ "base_amount": 0.0
+ })
- item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["amount"] += \
- flt(t.amount * multiply_based_on) / divide_based_on
+ multiply_based_on = d.basic_amount if total_basic_amount else d.qty
- item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["base_amount"] += \
- flt(t.base_amount * multiply_based_on) / divide_based_on
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["amount"] += \
+ flt(t.amount * multiply_based_on) / divide_based_on
+
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account]["base_amount"] += \
+ flt(t.base_amount * multiply_based_on) / divide_based_on
if item_account_wise_additional_cost:
for d in self.get("items"):
@@ -1191,13 +1205,88 @@ class StockEntry(StockController):
# item dict = { item_code: {qty, description, stock_uom} }
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=qty,
- fetch_exploded = 0, fetch_scrap_items = 1)
+ fetch_exploded = 0, fetch_scrap_items = 1) or {}
for item in itervalues(item_dict):
item.from_warehouse = ""
item.is_scrap_item = 1
+
+ for row in self.get_scrap_items_from_job_card():
+ if row.stock_qty <= 0:
+ continue
+
+ item_row = item_dict.get(row.item_code)
+ if not item_row:
+ item_row = frappe._dict({})
+
+ item_row.update({
+ 'uom': row.stock_uom,
+ 'from_warehouse': '',
+ 'qty': row.stock_qty + flt(item_row.stock_qty),
+ 'converison_factor': 1,
+ 'is_scrap_item': 1,
+ 'item_name': row.item_name,
+ 'description': row.description,
+ 'allow_zero_valuation_rate': 1
+ })
+
+ item_dict[row.item_code] = item_row
+
return item_dict
+ def get_scrap_items_from_job_card(self):
+ if not self.pro_doc:
+ self.set_work_order_details()
+
+ scrap_items = frappe.db.sql('''
+ SELECT
+ JCSI.item_code, JCSI.item_name, SUM(JCSI.stock_qty) as stock_qty, JCSI.stock_uom, JCSI.description
+ FROM
+ `tabJob Card` JC, `tabJob Card Scrap Item` JCSI
+ WHERE
+ JCSI.parent = JC.name AND JC.docstatus = 1
+ AND JCSI.item_code IS NOT NULL AND JC.work_order = %s
+ GROUP BY
+ JCSI.item_code
+ ''', self.work_order, as_dict=1)
+
+ pending_qty = flt(self.pro_doc.qty) - flt(self.pro_doc.produced_qty)
+ if pending_qty <=0:
+ return []
+
+ used_scrap_items = self.get_used_scrap_items()
+ for row in scrap_items:
+ row.stock_qty -= flt(used_scrap_items.get(row.item_code))
+ row.stock_qty = (row.stock_qty) * flt(self.fg_completed_qty) / flt(pending_qty)
+
+ if used_scrap_items.get(row.item_code):
+ used_scrap_items[row.item_code] -= row.stock_qty
+
+ if cint(frappe.get_cached_value('UOM', row.stock_uom, 'must_be_whole_number')):
+ row.stock_qty = frappe.utils.ceil(row.stock_qty)
+
+ return scrap_items
+
+ def get_used_scrap_items(self):
+ used_scrap_items = defaultdict(float)
+ data = frappe.get_all(
+ 'Stock Entry',
+ fields = [
+ '`tabStock Entry Detail`.`item_code`', '`tabStock Entry Detail`.`qty`'
+ ],
+ filters = [
+ ['Stock Entry', 'work_order', '=', self.work_order],
+ ['Stock Entry Detail', 'is_scrap_item', '=', 1],
+ ['Stock Entry', 'docstatus', '=', 1],
+ ['Stock Entry', 'purpose', 'in', ['Repack', 'Manufacture']]
+ ]
+ )
+
+ for row in data:
+ used_scrap_items[row.item_code] += row.qty
+
+ return used_scrap_items
+
def get_unconsumed_raw_materials(self):
wo = frappe.get_doc("Work Order", self.work_order)
wo_items = frappe.get_all('Work Order Item',
@@ -1264,9 +1353,9 @@ class StockEntry(StockController):
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
`tabWork Order` where name=%s""", self.work_order, as_dict=1)[0]
- manufacturing_qty = flt(po_qty.qty)
+ manufacturing_qty = flt(po_qty.qty) or 1
produced_qty = flt(po_qty.produced_qty)
- trans_qty = flt(po_qty.material_transferred_for_manufacturing)
+ trans_qty = flt(po_qty.material_transferred_for_manufacturing) or 1
for item in transferred_materials:
qty= item.qty
@@ -1417,8 +1506,8 @@ class StockEntry(StockController):
se_child.is_scrap_item = item_dict[d].get("is_scrap_item", 0)
se_child.is_process_loss = item_dict[d].get("is_process_loss", 0)
- for field in ["idx", "po_detail", "original_item",
- "expense_account", "description", "item_name", "serial_no", "batch_no"]:
+ for field in ["idx", "po_detail", "original_item", "expense_account",
+ "description", "item_name", "serial_no", "batch_no", "allow_zero_valuation_rate"]:
if item_dict[d].get(field):
se_child.set(field, item_dict[d].get(field))
@@ -1503,7 +1592,8 @@ class StockEntry(StockController):
qty_to_reserve -= reserved_qty[0][0]
if qty_to_reserve > 0:
for item in self.items:
- if item.item_code == item_code:
+ has_serial_no = frappe.get_cached_value("Item", item.item_code, "has_serial_no")
+ if item.item_code == item_code and has_serial_no:
serial_nos = (item.serial_no).split("\n")
for serial_no in serial_nos:
if qty_to_reserve > 0:
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 46619eb1f35..c9d0af5f3b1 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -837,6 +837,39 @@ class TestStockEntry(unittest.TestCase):
frappe.db.set_default("allow_negative_stock", 0)
+ def test_additional_cost_distribution_manufacture(self):
+ se = frappe.get_doc(
+ doctype="Stock Entry",
+ purpose="Manufacture",
+ additional_costs=[frappe._dict(base_amount=100)],
+ items=[
+ frappe._dict(item_code="RM", basic_amount=10),
+ frappe._dict(item_code="FG", basic_amount=20, t_warehouse="X", is_finished_item=1),
+ frappe._dict(item_code="scrap", basic_amount=30, t_warehouse="X")
+ ],
+ )
+
+ se.distribute_additional_costs()
+
+ distributed_costs = [d.additional_cost for d in se.items]
+ self.assertEqual([0.0, 100.0, 0.0], distributed_costs)
+
+ def test_additional_cost_distribution_non_manufacture(self):
+ se = frappe.get_doc(
+ doctype="Stock Entry",
+ purpose="Material Receipt",
+ additional_costs=[frappe._dict(base_amount=100)],
+ items=[
+ frappe._dict(item_code="RECEIVED_1", basic_amount=20, t_warehouse="X"),
+ frappe._dict(item_code="RECEIVED_2", basic_amount=30, t_warehouse="X")
+ ],
+ )
+
+ se.distribute_additional_costs()
+
+ distributed_costs = [d.additional_cost for d in se.items]
+ self.assertEqual([40.0, 60.0], distributed_costs)
+
def make_serialized_item(**args):
args = frappe._dict(args)
se = frappe.copy_doc(test_records[0])
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 2463a21ed61..2651407d16f 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -142,6 +142,7 @@
"oldfieldtype": "Data",
"print_width": "150px",
"read_only": 1,
+ "search_index": 1,
"width": "150px"
},
{
@@ -316,7 +317,7 @@
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-09-07 11:10:35.318872",
+ "modified": "2021-10-08 13:42:51.857631",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Ledger Entry",
@@ -338,4 +339,4 @@
],
"sort_field": "modified",
"sort_order": "DESC"
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index caa1d42b662..2cf71accf83 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -181,4 +181,4 @@ def on_doctype_update():
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
- frappe.db.add_index("Stock Ledger Entry", ["voucher_detail_no"])
+ frappe.db.add_index("Stock Ledger Entry", ["warehouse", "item_code"], "item_warehouse")
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 61bae49b0bd..ff33c2789b7 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -3,8 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.core.page.permission_manager.permission_manager import reset
from frappe.utils import add_days, today
@@ -21,9 +19,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
create_stock_reconciliation,
)
from erpnext.stock.stock_ledger import get_previous_sle
+from erpnext.tests.utils import ERPNextTestCase
-class TestStockLedgerEntry(unittest.TestCase):
+class TestStockLedgerEntry(ERPNextTestCase):
def setUp(self):
items = create_items()
reset('Stock Entry')
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index fa96c5a09b0..f59a4e6ff85 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -619,6 +619,11 @@ def get_stock_balance_for(item_code, warehouse,
item_dict = frappe.db.get_value("Item", item_code,
["has_serial_no", "has_batch_no"], as_dict=1)
+ if not item_dict:
+ # In cases of data upload to Items table
+ msg = _("Item {} does not exist.").format(item_code)
+ frappe.throw(msg, title=_("Missing"))
+
serial_nos = ""
with_serial_no = True if item_dict.get("has_serial_no") else False
data = get_stock_balance(item_code, warehouse, posting_date, posting_time,
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index 8647bee40ec..415ac5eb267 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -6,8 +6,6 @@
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.utils import add_days, flt, nowdate, nowtime, random_string
@@ -22,12 +20,13 @@ from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
-from erpnext.tests.utils import change_settings
+from erpnext.tests.utils import ERPNextTestCase, change_settings
-class TestStockReconciliation(unittest.TestCase):
+class TestStockReconciliation(ERPNextTestCase):
@classmethod
def setUpClass(self):
+ super().setUpClass()
create_batch_or_serial_no_items()
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@@ -372,7 +371,6 @@ class TestStockReconciliation(unittest.TestCase):
"""
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.stock_ledger import NegativeStockError
- frappe.db.commit()
item_code = "Backdated-Reco-Cancellation-Item"
warehouse = "_Test Warehouse - _TC"
@@ -395,10 +393,6 @@ class TestStockReconciliation(unittest.TestCase):
repost_exists = bool(frappe.db.exists("Repost Item Valuation", {"voucher_no": sr.name}))
self.assertFalse(repost_exists, msg="Negative stock validation not working on reco cancellation")
- # teardown
- frappe.db.rollback()
-
-
def test_valid_batch(self):
create_batch_item_with_batch("Testing Batch Item 1", "001")
create_batch_item_with_batch("Testing Batch Item 2", "002")
diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/__init__.py b/erpnext/stock/doctype/stock_reposting_settings/__init__.py
similarity index 100%
rename from erpnext/healthcare/doctype/healthcare_service_unit_type/__init__.py
rename to erpnext/stock/doctype/stock_reposting_settings/__init__.py
diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js
new file mode 100644
index 00000000000..42d0723d427
--- /dev/null
+++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Stock Reposting Settings', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json
new file mode 100644
index 00000000000..24740590037
--- /dev/null
+++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.json
@@ -0,0 +1,72 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2021-10-01 10:56:30.814787",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "scheduling_section",
+ "limit_reposting_timeslot",
+ "start_time",
+ "end_time",
+ "limits_dont_apply_on"
+ ],
+ "fields": [
+ {
+ "fieldname": "scheduling_section",
+ "fieldtype": "Section Break",
+ "label": "Scheduling"
+ },
+ {
+ "depends_on": "limit_reposting_timeslot",
+ "fieldname": "start_time",
+ "fieldtype": "Time",
+ "label": "Start Time",
+ "mandatory_depends_on": "limit_reposting_timeslot"
+ },
+ {
+ "depends_on": "limit_reposting_timeslot",
+ "fieldname": "end_time",
+ "fieldtype": "Time",
+ "label": "End Time",
+ "mandatory_depends_on": "limit_reposting_timeslot"
+ },
+ {
+ "depends_on": "limit_reposting_timeslot",
+ "fieldname": "limits_dont_apply_on",
+ "fieldtype": "Select",
+ "label": "Limits don't apply on",
+ "options": "\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday"
+ },
+ {
+ "default": "0",
+ "fieldname": "limit_reposting_timeslot",
+ "fieldtype": "Check",
+ "label": "Limit timeslot for Stock Reposting"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2021-10-01 11:27:28.981594",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Stock Reposting Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py
new file mode 100644
index 00000000000..bab521d69fc
--- /dev/null
+++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from frappe.model.document import Document
+from frappe.utils import add_to_date, get_datetime, get_time_str, time_diff_in_hours
+
+
+class StockRepostingSettings(Document):
+
+
+ def validate(self):
+ self.set_minimum_reposting_time_slot()
+
+ def set_minimum_reposting_time_slot(self):
+ """Ensure that timeslot for reposting is at least 12 hours."""
+ if not self.limit_reposting_timeslot:
+ return
+
+ start_time = get_datetime(self.start_time)
+ end_time = get_datetime(self.end_time)
+
+ if start_time > end_time:
+ end_time = add_to_date(end_time, days=1, as_datetime=True)
+
+ diff = time_diff_in_hours(end_time, start_time)
+
+ if diff < 10:
+ self.end_time = get_time_str(add_to_date(self.start_time, hours=10, as_datetime=True))
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py b/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py
similarity index 70%
rename from erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
rename to erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py
index b8a1dd77869..fad74d355cf 100644
--- a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
+++ b/erpnext/stock/doctype/stock_reposting_settings/test_stock_reposting_settings.py
@@ -5,5 +5,5 @@
import unittest
-class TestTreatmentPlanTemplate(unittest.TestCase):
+class TestStockRepostingSettings(unittest.TestCase):
pass
diff --git a/erpnext/stock/doctype/stock_settings/test_stock_settings.py b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
index 7e8090499fb..bf8ac5dc79a 100644
--- a/erpnext/stock/doctype/stock_settings/test_stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/test_stock_settings.py
@@ -7,9 +7,12 @@ import unittest
import frappe
+from erpnext.tests.utils import ERPNextTestCase
-class TestStockSettings(unittest.TestCase):
+
+class TestStockSettings(ERPNextTestCase):
def setUp(self):
+ super().setUp()
frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)
def test_settings(self):
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index 1ca7181f279..98317ec9c57 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -2,8 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import unittest
-
import frappe
from frappe.test_runner import make_test_records
from frappe.utils import cint
@@ -12,11 +10,13 @@ import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.tests.utils import ERPNextTestCase
test_records = frappe.get_test_records('Warehouse')
-class TestWarehouse(unittest.TestCase):
+class TestWarehouse(ERPNextTestCase):
def setUp(self):
+ super().setUp()
if not frappe.get_value('Item', '_Test Item'):
make_test_records('Item')
diff --git a/erpnext/stock/form_tour/material_request/material_request.json b/erpnext/stock/form_tour/material_request/material_request.json
new file mode 100644
index 00000000000..145b4a06c2b
--- /dev/null
+++ b/erpnext/stock/form_tour/material_request/material_request.json
@@ -0,0 +1,97 @@
+{
+ "creation": "2021-07-29 12:32:08.929900",
+ "docstatus": 0,
+ "doctype": "Form Tour",
+ "idx": 0,
+ "is_standard": 1,
+ "modified": "2021-10-05 13:11:13.119453",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Material Request",
+ "owner": "Administrator",
+ "reference_doctype": "Material Request",
+ "save_on_complete": 1,
+ "steps": [
+ {
+ "description": "The purpose of the material request can be selected here. For now select \"Purchase\" as the purpose.",
+ "field": "",
+ "fieldname": "material_request_type",
+ "fieldtype": "Select",
+ "has_next_condition": 1,
+ "is_table_field": 0,
+ "label": "Purpose",
+ "next_step_condition": "eval: doc.material_request_type == \"Purchase\"",
+ "parent_field": "",
+ "position": "Bottom",
+ "title": "Purpose"
+ },
+ {
+ "description": "Set the \"Required By\" date for the materials. This sets the \"Required By\" date for all the items.",
+ "field": "",
+ "fieldname": "schedule_date",
+ "fieldtype": "Date",
+ "has_next_condition": 0,
+ "is_table_field": 0,
+ "label": "Required By",
+ "next_step_condition": "",
+ "parent_field": "",
+ "position": "Left",
+ "title": "Required By"
+ },
+ {
+ "description": "Setting the target warehouse sets it for all the items.",
+ "field": "",
+ "fieldname": "set_warehouse",
+ "fieldtype": "Link",
+ "has_next_condition": 0,
+ "is_table_field": 0,
+ "label": "Set Target Warehouse",
+ "next_step_condition": "",
+ "parent_field": "",
+ "position": "Left",
+ "title": "Target Warehouse"
+ },
+ {
+ "description": "Items table",
+ "field": "",
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "has_next_condition": 0,
+ "is_table_field": 0,
+ "label": "Items",
+ "parent_field": "",
+ "position": "Bottom",
+ "title": "Items"
+ },
+ {
+ "child_doctype": "Material Request Item",
+ "description": "Select an Item code. Item details will be fetched automatically.",
+ "field": "",
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "has_next_condition": 1,
+ "is_table_field": 1,
+ "label": "Item Code",
+ "next_step_condition": "eval: doc.item_code",
+ "parent_field": "",
+ "parent_fieldname": "items",
+ "position": "Right",
+ "title": "Item Code"
+ },
+ {
+ "child_doctype": "Material Request Item",
+ "description": "Enter the required quantity for the material.",
+ "field": "",
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "has_next_condition": 0,
+ "is_table_field": 1,
+ "label": "Quantity",
+ "parent_field": "",
+ "parent_fieldname": "items",
+ "position": "Bottom",
+ "title": "Quantity"
+ }
+ ],
+ "title": "Material Request"
+}
\ No newline at end of file
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 19597c3d993..e0190b64a75 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -89,7 +89,13 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
out.update(get_bin_details(args.item_code, args.get("from_warehouse")))
elif out.get("warehouse"):
- out.update(get_bin_details(args.item_code, out.warehouse, args.company))
+ if doc and doc.get('doctype') == 'Purchase Order':
+ # calculate company_total_stock only for po
+ bin_details = get_bin_details(args.item_code, out.warehouse, args.company)
+ else:
+ bin_details = get_bin_details(args.item_code, out.warehouse)
+
+ out.update(bin_details)
# update args with out, if key or value not exists
for key, value in iteritems(out):
@@ -382,7 +388,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
return out
-def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
+def get_item_warehouse(item, args, overwrite_warehouse, defaults=None):
if not defaults:
defaults = frappe._dict({
'item_defaults' : get_item_defaults(item.name, args.company),
@@ -485,8 +491,9 @@ def get_item_tax_template(args, item, out):
"item_tax_template": None
}
"""
- item_tax_template = args.get("item_tax_template")
- item_tax_template = _get_item_tax_template(args, item.taxes, out)
+ item_tax_template = None
+ if item.taxes:
+ item_tax_template = _get_item_tax_template(args, item.taxes, out)
if not item_tax_template:
item_group = item.item_group
@@ -502,17 +509,17 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False):
taxes_with_no_validity = []
for tax in taxes:
- tax_company = frappe.get_value("Item Tax Template", tax.item_tax_template, 'company')
- if (tax.valid_from or tax.maximum_net_rate) and tax_company == args['company']:
- # In purchase Invoice first preference will be given to supplier invoice date
- # if supplier date is not present then posting date
- validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
+ tax_company = frappe.get_cached_value("Item Tax Template", tax.item_tax_template, 'company')
+ if tax_company == args['company']:
+ if (tax.valid_from or tax.maximum_net_rate):
+ # In purchase Invoice first preference will be given to supplier invoice date
+ # if supplier date is not present then posting date
+ validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
- if getdate(tax.valid_from) <= getdate(validation_date) \
- and is_within_valid_range(args, tax):
- taxes_with_validity.append(tax)
- else:
- if tax_company == args['company']:
+ if getdate(tax.valid_from) <= getdate(validation_date) \
+ and is_within_valid_range(args, tax):
+ taxes_with_validity.append(tax)
+ else:
taxes_with_no_validity.append(tax)
if taxes_with_validity:
@@ -890,8 +897,7 @@ def get_pos_profile_item_details(company, args, pos_profile=None, update_data=Fa
res[fieldname] = pos_profile.get(fieldname)
if res.get("warehouse"):
- res.actual_qty = get_bin_details(args.item_code,
- res.warehouse).get("actual_qty")
+ res.actual_qty = get_bin_details(args.item_code, res.warehouse).get("actual_qty")
return res
diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py
index 3cd4cd27617..7c6fbfd9cd1 100644
--- a/erpnext/stock/reorder_item.py
+++ b/erpnext/stock/reorder_item.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import json
+from math import ceil
import frappe
from frappe import _
@@ -149,11 +150,16 @@ def create_material_request(material_requests):
conversion_factor = frappe.db.get_value("UOM Conversion Detail",
{'parent': item.name, 'uom': uom}, 'conversion_factor') or 1.0
+ must_be_whole_number = frappe.db.get_value("UOM", uom, "must_be_whole_number", cache=True)
+ qty = d.reorder_qty / conversion_factor
+ if must_be_whole_number:
+ qty = ceil(qty)
+
mr.append("items", {
"doctype": "Material Request Item",
"item_code": d.item_code,
"schedule_date": add_days(nowdate(),cint(item.lead_time_days)),
- "qty": d.reorder_qty / conversion_factor,
+ "qty": qty,
"uom": uom,
"stock_uom": item.stock_uom,
"warehouse": d.warehouse,
diff --git a/erpnext/stock/report/process_loss_report/__init__.py b/erpnext/stock/report/process_loss_report/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.js b/erpnext/stock/report/stock_ageing/stock_ageing.js
index b22788f7a29..db463b7ca09 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.js
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.js
@@ -22,7 +22,15 @@ frappe.query_reports["Stock Ageing"] = {
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
- "options": "Warehouse"
+ "options": "Warehouse",
+ get_query: () => {
+ const company = frappe.query_report.get_filter_value("company");
+ return {
+ filters: {
+ ...company && {company},
+ }
+ };
+ }
},
{
"fieldname":"item_code",
diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
index 21e1205bfcc..32df5859375 100644
--- a/erpnext/stock/report/stock_analytics/test_stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
@@ -5,9 +5,10 @@ from frappe import _dict
from erpnext.accounts.utils import get_fiscal_year
from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
+from erpnext.tests.utils import ERPNextTestCase
-class TestStockAnalyticsReport(unittest.TestCase):
+class TestStockAnalyticsReport(ERPNextTestCase):
def test_get_period_date_ranges(self):
filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06")
diff --git a/erpnext/stock/report/stock_balance/stock_balance.js b/erpnext/stock/report/stock_balance/stock_balance.js
index 7d22823eb80..ce6ffa0b914 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.js
+++ b/erpnext/stock/report/stock_balance/stock_balance.js
@@ -53,13 +53,14 @@ frappe.query_reports["Stock Balance"] = {
"width": "80",
"options": "Warehouse",
get_query: () => {
- var warehouse_type = frappe.query_report.get_filter_value('warehouse_type');
- if(warehouse_type){
- return {
- filters: {
- 'warehouse_type': warehouse_type
- }
- };
+ let warehouse_type = frappe.query_report.get_filter_value("warehouse_type");
+ let company = frappe.query_report.get_filter_value("company");
+
+ return {
+ filters: {
+ ...warehouse_type && {warehouse_type},
+ ...company && {company}
+ }
}
}
},
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index fc5d5c12da4..bb53c557371 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -202,7 +202,9 @@ def get_item_warehouse_map(filters, sle):
value_diff = flt(d.stock_value_difference)
- if d.posting_date < from_date:
+ if d.posting_date < from_date or (d.posting_date == from_date
+ and d.voucher_type == "Stock Reconciliation" and
+ frappe.db.get_value("Stock Reconciliation", d.voucher_no, "purpose") == "Opening Stock"):
qty_dict.opening_qty += qty_diff
qty_dict.opening_val += value_diff
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 1ea58fed191..4e20b472617 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -21,7 +21,7 @@ def execute(filters=None):
items = get_items(filters)
sl_entries = get_stock_ledger_entries(filters, items)
item_details = get_item_details(items, sl_entries, include_uom)
- opening_row = get_opening_balance(filters, columns)
+ opening_row = get_opening_balance(filters, columns, sl_entries)
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
data = []
@@ -218,7 +218,7 @@ def get_sle_conditions(filters):
return "and {}".format(" and ".join(conditions)) if conditions else ""
-def get_opening_balance(filters, columns):
+def get_opening_balance(filters, columns, sl_entries):
if not (filters.item_code and filters.warehouse and filters.from_date):
return
@@ -230,6 +230,15 @@ def get_opening_balance(filters, columns):
"posting_time": "00:00:00"
})
+ # check if any SLEs are actually Opening Stock Reconciliation
+ for sle in sl_entries:
+ if (sle.get("voucher_type") == "Stock Reconciliation"
+ and sle.get("date").split()[0] == filters.from_date
+ and frappe.db.get_value("Stock Reconciliation", sle.voucher_no, "purpose") == "Opening Stock"
+ ):
+ last_entry = sle
+ sl_entries.remove(sle)
+
row = {
"item_code": _("'Opening'"),
"qty_after_transaction": last_entry.get("qty_after_transaction", 0),
diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py
new file mode 100644
index 00000000000..d7fb5b2bf3f
--- /dev/null
+++ b/erpnext/stock/report/test_reports.py
@@ -0,0 +1,63 @@
+import unittest
+from typing import List, Tuple
+
+from erpnext.tests.utils import ReportFilters, ReportName, execute_script_report
+
+DEFAULT_FILTERS = {
+ "company": "_Test Company",
+ "from_date": "2010-01-01",
+ "to_date": "2030-01-01",
+}
+
+
+REPORT_FILTER_TEST_CASES: List[Tuple[ReportName, ReportFilters]] = [
+ ("Stock Ledger", {"_optional": True}),
+ ("Stock Balance", {"_optional": True}),
+ ("Stock Projected Qty", {"_optional": True}),
+ ("Batch-Wise Balance History", {}),
+ ("Itemwise Recommended Reorder Level", {"item_group": "All Item Groups"}),
+ ("COGS By Item Group", {}),
+ ("Stock Qty vs Serial No Count", {"warehouse": "_Test Warehouse - _TC"}),
+ (
+ "Stock and Account Value Comparison",
+ {
+ "company": "_Test Company with perpetual inventory",
+ "account": "Stock In Hand - TCP1",
+ "as_on_date": "2021-01-01",
+ },
+ ),
+ ("Product Bundle Balance", {"date": "2022-01-01", "_optional": True}),
+ (
+ "Stock Analytics",
+ {
+ "from_date": "2021-01-01",
+ "to_date": "2021-12-31",
+ "value_quantity": "Quantity",
+ "_optional": True,
+ },
+ ),
+ ("Warehouse wise Item Balance Age and Value", {"_optional": True}),
+ ("Item Variant Details", {"item": "_Test Variant Item",}),
+ ("Total Stock Summary", {"group_by": "warehouse",}),
+ ("Batch Item Expiry Status", {}),
+ ("Stock Ageing", {"range1": 30, "range2": 60, "range3": 90, "_optional": True}),
+]
+
+OPTIONAL_FILTERS = {
+ "warehouse": "_Test Warehouse - _TC",
+ "item": "_Test Item",
+ "item_group": "_Test Item Group",
+}
+
+
+class TestReports(unittest.TestCase):
+ def test_execute_all_stock_reports(self):
+ """Test that all script report in stock modules are executable with supported filters"""
+ for report, filter in REPORT_FILTER_TEST_CASES:
+ execute_script_report(
+ report_name=report,
+ module="Stock",
+ filters=filter,
+ default_filters=DEFAULT_FILTERS,
+ optional_filters=OPTIONAL_FILTERS if filter.get("_optional") else None,
+ )
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 542124204b5..70f4bcaef79 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -13,8 +13,8 @@ from six import iteritems
import erpnext
from erpnext.stock.utils import (
- get_bin,
get_incoming_outgoing_rate_for_cancel,
+ get_or_make_bin,
get_valuation_method,
)
@@ -123,12 +123,11 @@ def set_as_cancel(voucher_type, voucher_no):
(now(), frappe.session.user, voucher_type, voucher_no))
def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
- args.update({"doctype": "Stock Ledger Entry"})
+ args["doctype"] = "Stock Ledger Entry"
sle = frappe.get_doc(args)
sle.flags.ignore_permissions = 1
sle.allow_negative_stock=allow_negative_stock
sle.via_landed_cost_voucher = via_landed_cost_voucher
- sle.insert()
sle.submit()
return sle
@@ -407,7 +406,8 @@ class update_entries_after(object):
return
# Get dynamic incoming/outgoing rate
- self.get_dynamic_incoming_outgoing_rate(sle)
+ if not self.args.get("sle_id"):
+ self.get_dynamic_incoming_outgoing_rate(sle)
if sle.serial_no:
self.get_serialized_values(sle)
@@ -447,7 +447,8 @@ class update_entries_after(object):
sle.doctype="Stock Ledger Entry"
frappe.get_doc(sle).db_update()
- self.update_outgoing_rate_on_transaction(sle)
+ if not self.args.get("sle_id"):
+ self.update_outgoing_rate_on_transaction(sle)
def validate_negative_stock(self, sle):
"""
@@ -599,7 +600,7 @@ class update_entries_after(object):
if not allow_zero_rate:
self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
- currency=erpnext.get_company_currency(sle.company))
+ currency=erpnext.get_company_currency(sle.company), company=sle.company)
def get_incoming_value_for_serial_nos(self, sle, serial_nos):
# get rate from serial nos within same company
@@ -666,7 +667,7 @@ class update_entries_after(object):
if not allow_zero_valuation_rate:
self.wh_data.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
- currency=erpnext.get_company_currency(sle.company))
+ currency=erpnext.get_company_currency(sle.company), company=sle.company)
def get_fifo_values(self, sle):
incoming_rate = flt(sle.incoming_rate)
@@ -681,11 +682,15 @@ class update_entries_after(object):
if self.wh_data.stock_queue[-1][1]==incoming_rate:
self.wh_data.stock_queue[-1][0] += actual_qty
else:
+ # Item has a positive balance qty, add new entry
if self.wh_data.stock_queue[-1][0] > 0:
self.wh_data.stock_queue.append([actual_qty, incoming_rate])
- else:
+ else: # negative balance qty
qty = self.wh_data.stock_queue[-1][0] + actual_qty
- self.wh_data.stock_queue[-1] = [qty, incoming_rate]
+ if qty > 0: # new balance qty is positive
+ self.wh_data.stock_queue[-1] = [qty, incoming_rate]
+ else: # new balance qty is still negative, maintain same rate
+ self.wh_data.stock_queue[-1][0] = qty
else:
qty_to_pop = abs(actual_qty)
while qty_to_pop:
@@ -695,7 +700,7 @@ class update_entries_after(object):
if not allow_zero_valuation_rate:
_rate = get_valuation_rate(sle.item_code, sle.warehouse,
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
- currency=erpnext.get_company_currency(sle.company))
+ currency=erpnext.get_company_currency(sle.company), company=sle.company)
else:
_rate = 0
@@ -799,14 +804,13 @@ class update_entries_after(object):
def update_bin(self):
# update bin for each warehouse
for warehouse, data in iteritems(self.data):
- bin_doc = get_bin(self.item_code, warehouse)
- bin_doc.update({
+ bin_record = get_or_make_bin(self.item_code, warehouse)
+
+ frappe.db.set_value('Bin', bin_record, {
"valuation_rate": data.valuation_rate,
"actual_qty": data.qty_after_transaction,
"stock_value": data.stock_value
})
- bin_doc.flags.via_stock_ledger_entry = True
- bin_doc.save(ignore_permissions=True)
def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False):
@@ -907,12 +911,13 @@ def get_sle_by_voucher_detail_no(voucher_detail_no, excluded_sle=None):
def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
allow_zero_rate=False, currency=None, company=None, raise_error_if_no_rate=True):
- # Get valuation rate from last sle for the same item and warehouse
- if not company:
- company = erpnext.get_default_company()
+ if not company:
+ company = frappe.get_cached_value("Warehouse", warehouse, "company")
+
+ # Get valuation rate from last sle for the same item and warehouse
last_valuation_rate = frappe.db.sql("""select valuation_rate
- from `tabStock Ledger Entry`
+ from `tabStock Ledger Entry` force index (item_warehouse)
where
item_code = %s
AND warehouse = %s
@@ -923,7 +928,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
if not last_valuation_rate:
# Get valuation rate from last sle for the item against any warehouse
last_valuation_rate = frappe.db.sql("""select valuation_rate
- from `tabStock Ledger Entry`
+ from `tabStock Ledger Entry` force index (item_code)
where
item_code = %s
AND valuation_rate > 0
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index aeb06e987f8..e1d5a89082e 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -101,11 +101,7 @@ def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None
if with_valuation_rate:
if with_serial_no:
- serial_nos = last_entry.get("serial_no")
-
- if (serial_nos and
- len(get_serial_nos_data(serial_nos)) < last_entry.qty_after_transaction):
- serial_nos = get_serial_nos_data_after_transactions(args)
+ serial_nos = get_serial_nos_data_after_transactions(args)
return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
if last_entry else (0.0, 0.0, 0.0))
@@ -115,19 +111,32 @@ def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None
return last_entry.qty_after_transaction if last_entry else 0.0
def get_serial_nos_data_after_transactions(args):
- serial_nos = []
- data = frappe.db.sql(""" SELECT serial_no, actual_qty
- FROM `tabStock Ledger Entry`
- WHERE
- item_code = %(item_code)s and warehouse = %(warehouse)s
- and timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)
- order by posting_date, posting_time asc """, args, as_dict=1)
+ from pypika import CustomFunction
- for d in data:
- if d.actual_qty > 0:
- serial_nos.extend(get_serial_nos_data(d.serial_no))
+ serial_nos = set()
+ args = frappe._dict(args)
+ sle = frappe.qb.DocType('Stock Ledger Entry')
+ Timestamp = CustomFunction('timestamp', ['date', 'time'])
+
+ stock_ledger_entries = frappe.qb.from_(
+ sle
+ ).select(
+ 'serial_no','actual_qty'
+ ).where(
+ (sle.item_code == args.item_code)
+ & (sle.warehouse == args.warehouse)
+ & (Timestamp(sle.posting_date, sle.posting_time) < Timestamp(args.posting_date, args.posting_time))
+ & (sle.is_cancelled == 0)
+ ).orderby(
+ sle.posting_date, sle.posting_time, sle.creation
+ ).run(as_dict=1)
+
+ for stock_ledger_entry in stock_ledger_entries:
+ changed_serial_no = get_serial_nos_data(stock_ledger_entry.serial_no)
+ if stock_ledger_entry.actual_qty > 0:
+ serial_nos.update(changed_serial_no)
else:
- serial_nos = list(set(serial_nos) - set(get_serial_nos_data(d.serial_no)))
+ serial_nos.difference_update(changed_serial_no)
return '\n'.join(serial_nos)
@@ -180,12 +189,27 @@ def get_bin(item_code, warehouse):
bin_obj.flags.ignore_permissions = True
return bin_obj
+def get_or_make_bin(item_code, warehouse) -> str:
+ bin_record = frappe.db.get_value('Bin', {'item_code': item_code, 'warehouse': warehouse})
+
+ if not bin_record:
+ bin_obj = frappe.get_doc({
+ "doctype": "Bin",
+ "item_code": item_code,
+ "warehouse": warehouse,
+ })
+ bin_obj.flags.ignore_permissions = 1
+ bin_obj.insert()
+ bin_record = bin_obj.name
+
+ return bin_record
+
def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False):
+ from erpnext.stock.doctype.bin.bin import update_stock
is_stock_item = frappe.get_cached_value('Item', args.get("item_code"), 'is_stock_item')
if is_stock_item:
- bin = get_bin(args.get("item_code"), args.get("warehouse"))
- bin.update_stock(args, allow_negative_stock, via_landed_cost_voucher)
- return bin
+ bin_record = get_or_make_bin(args.get("item_code"), args.get("warehouse"))
+ update_stock(bin_record, args, allow_negative_stock, via_landed_cost_voucher)
else:
frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code")))
diff --git a/erpnext/stock/workspace/stock/stock.json b/erpnext/stock/workspace/stock/stock.json
index 26d10ce7038..9c805150f19 100644
--- a/erpnext/stock/workspace/stock/stock.json
+++ b/erpnext/stock/workspace/stock/stock.json
@@ -1,6 +1,4 @@
{
- "cards_label": "Masters & Reports",
- "category": "",
"charts": [
{
"chart_name": "Warehouse wise Stock Value"
@@ -8,18 +6,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Stock\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": null, \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Quick Access\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Material Request\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Receipt\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Delivery Note\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Ledger\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Stock Balance\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Masters & Reports\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Items and Pricing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Stock Transactions\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Stock Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Serial No and Batch\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Incorrect Data Report\", \"col\": 4}}]",
"creation": "2020-03-02 15:43:10.096528",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "stock",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Stock",
"links": [
{
@@ -764,15 +756,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:02.361509",
+ "modified": "2021-08-05 12:16:02.361519",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock",
- "onboarding": "Stock",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
@@ -831,6 +820,5 @@
"type": "Dashboard"
}
],
- "shortcuts_label": "Quick Access",
"title": "Stock"
}
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index 7d7399d097c..0fe1068a76c 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -228,7 +228,7 @@ def get_time_in_timedelta(time):
def set_first_response_time(communication, method):
if communication.get('reference_doctype') == "Issue":
issue = get_parent_doc(communication)
- if is_first_response(issue):
+ if is_first_response(issue) and issue.service_level_agreement:
first_response_time = calculate_first_response_time(issue, get_datetime(issue.first_responded_on))
issue.db_set("first_response_time", first_response_time)
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index b649b8768bb..5f470aad672 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -203,10 +203,11 @@
}
],
"links": [],
- "modified": "2021-07-27 11:16:45.596579",
+ "modified": "2021-10-02 11:32:55.556024",
"modified_by": "Administrator",
"module": "Support",
"name": "Service Level Agreement",
+ "naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
@@ -237,4 +238,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index bd478119b63..6bdd8f2205c 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -339,7 +339,7 @@ def set_documents_with_active_service_level_agreement():
def apply(doc, method=None):
# Applies SLA to document on validate
- if frappe.flags.in_patch or frappe.flags.in_install or frappe.flags.in_setup_wizard or \
+ if frappe.flags.in_patch or frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_setup_wizard or \
doc.doctype not in get_documents_with_active_service_level_agreement():
return
diff --git a/erpnext/support/doctype/support_settings/support_settings.json b/erpnext/support/doctype/support_settings/support_settings.json
index 5d3d3ace59d..bf1daa16f86 100644
--- a/erpnext/support/doctype/support_settings/support_settings.json
+++ b/erpnext/support/doctype/support_settings/support_settings.json
@@ -37,7 +37,6 @@
},
{
"default": "7",
- "description": "Auto close Issue after 7 days",
"fieldname": "close_issue_after_days",
"fieldtype": "Int",
"label": "Close Issue After Days"
@@ -164,7 +163,7 @@
],
"issingle": 1,
"links": [],
- "modified": "2020-06-11 13:08:38.473616",
+ "modified": "2021-10-14 13:08:38.473616",
"modified_by": "Administrator",
"module": "Support",
"name": "Support Settings",
@@ -185,4 +184,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/support/workspace/support/support.json b/erpnext/support/workspace/support/support.json
index 4c5829d7a03..d68c7c70cf7 100644
--- a/erpnext/support/workspace/support/support.json
+++ b/erpnext/support/workspace/support/support.json
@@ -1,20 +1,13 @@
{
- "category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Issue\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Maintenance Visit\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Service Level Agreement\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Issues\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Maintenance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Service Level Agreement\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Warranty\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
"creation": "2020-03-02 15:48:23.224699",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "support",
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Support",
"links": [
{
@@ -176,15 +169,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:02.699923",
+ "modified": "2021-08-05 12:16:02.699924",
"modified_by": "Administrator",
"module": "Support",
"name": "Support",
- "onboarding": "",
"owner": "Administrator",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
diff --git a/erpnext/templates/emails/holiday_reminder.html b/erpnext/templates/emails/holiday_reminder.html
index e38d27bf8bc..bbef6be6728 100644
--- a/erpnext/templates/emails/holiday_reminder.html
+++ b/erpnext/templates/emails/holiday_reminder.html
@@ -11,6 +11,6 @@
{% endfor %}
{% else %}
- You don't have no upcoming holidays this {{ frequency }}.
+ You have no upcoming holidays this {{ frequency }}.
{% endif %}
{% endif %}
diff --git a/erpnext/templates/print_formats/includes/taxes_and_charges.html b/erpnext/templates/print_formats/includes/taxes_and_charges.html
new file mode 100644
index 00000000000..0d8e3834d81
--- /dev/null
+++ b/erpnext/templates/print_formats/includes/taxes_and_charges.html
@@ -0,0 +1,34 @@
+{% macro render_row(label, value) %}
+
+{% endmacro %}
+
+{%- macro render_discount_amount(doc) -%}
+ {%- if doc.discount_amount -%}
+ {{ render_row(_(doc.meta.get_label('discount_amount')), '- ' + doc.get_formatted("discount_amount", doc)) }}
+ {%- endif -%}
+{%- endmacro -%}
+
+
+
+
+ {%- if doc.apply_discount_on == "Net Total" -%}
+ {{ render_discount_amount(doc) }}
+ {%- endif -%}
+ {%- for charge in doc.taxes -%}
+ {%- if (charge.tax_amount or print_settings.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
+ {{ render_row(charge.get_formatted("description"), charge.get_formatted('tax_amount', doc)) }}
+ {%- endif -%}
+ {%- endfor -%}
+ {%- if doc.apply_discount_on == "Grand Total" -%}
+ {{ render_discount_amount(doc) }}
+ {%- endif -%}
+
+
+
diff --git a/erpnext/templates/print_formats/includes/total.html b/erpnext/templates/print_formats/includes/total.html
index 81799809ba7..879203bbf25 100644
--- a/erpnext/templates/print_formats/includes/total.html
+++ b/erpnext/templates/print_formats/includes/total.html
@@ -7,7 +7,7 @@
{% else %}
- {{ _(doc.meta.get_label('total')) }}
+
{{ _(df.label) }}
{{ doc.get_formatted("total", doc) }}
diff --git a/erpnext/tests/test_webform.py b/erpnext/tests/test_webform.py
new file mode 100644
index 00000000000..19255db33c5
--- /dev/null
+++ b/erpnext/tests/test_webform.py
@@ -0,0 +1,138 @@
+import unittest
+
+import frappe
+
+from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+
+
+class TestWebsite(unittest.TestCase):
+ def test_permission_for_custom_doctype(self):
+ create_user('Supplier 1', 'supplier1@gmail.com')
+ create_user('Supplier 2', 'supplier2@gmail.com')
+ create_supplier_with_contact('Supplier1', 'All Supplier Groups', 'Supplier 1', 'supplier1@gmail.com')
+ create_supplier_with_contact('Supplier2', 'All Supplier Groups', 'Supplier 2', 'supplier2@gmail.com')
+ po1 = create_purchase_order(supplier='Supplier1')
+ po2 = create_purchase_order(supplier='Supplier2')
+
+ create_custom_doctype()
+ create_webform()
+ create_order_assignment(supplier='Supplier1', po = po1.name)
+ create_order_assignment(supplier='Supplier2', po = po2.name)
+
+ frappe.set_user("Administrator")
+ # checking if data consist of all order assignment of Supplier1 and Supplier2
+ self.assertTrue('Supplier1' and 'Supplier2' in [data.supplier for data in get_data()])
+
+ frappe.set_user("supplier1@gmail.com")
+ # checking if data only consist of order assignment of Supplier1
+ self.assertTrue('Supplier1' in [data.supplier for data in get_data()])
+ self.assertFalse([data.supplier for data in get_data() if data.supplier != 'Supplier1'])
+
+ frappe.set_user("supplier2@gmail.com")
+ # checking if data only consist of order assignment of Supplier2
+ self.assertTrue('Supplier2' in [data.supplier for data in get_data()])
+ self.assertFalse([data.supplier for data in get_data() if data.supplier != 'Supplier2'])
+
+ frappe.set_user("Administrator")
+
+def get_data():
+ webform_list_contexts = frappe.get_hooks('webform_list_context')
+ if webform_list_contexts:
+ context = frappe._dict(frappe.get_attr(webform_list_contexts[0])('Buying') or {})
+ kwargs = dict(doctype='Order Assignment', order_by = 'modified desc')
+ return context.get_list(**kwargs)
+
+def create_user(name, email):
+ frappe.get_doc({
+ 'doctype': 'User',
+ 'send_welcome_email': 0,
+ 'user_type': 'Website User',
+ 'first_name': name,
+ 'email': email,
+ 'roles': [{"doctype": "Has Role", "role": "Supplier"}]
+ }).insert(ignore_if_duplicate = True)
+
+def create_supplier_with_contact(name, group, contact_name, contact_email):
+ supplier = frappe.get_doc({
+ 'doctype': 'Supplier',
+ 'supplier_name': name,
+ 'supplier_group': group
+ }).insert(ignore_if_duplicate = True)
+
+ if not frappe.db.exists('Contact', contact_name+'-1-'+name):
+ new_contact = frappe.new_doc("Contact")
+ new_contact.first_name = contact_name
+ new_contact.is_primary_contact = True,
+ new_contact.append('links', {
+ "link_doctype": "Supplier",
+ "link_name": supplier.name
+ })
+ new_contact.append('email_ids', {
+ "email_id": contact_email,
+ "is_primary": 1
+ })
+
+ new_contact.insert(ignore_mandatory=True)
+
+def create_custom_doctype():
+ frappe.get_doc({
+ 'doctype': 'DocType',
+ 'name': 'Order Assignment',
+ 'module': 'Buying',
+ 'custom': 1,
+ 'autoname': 'field:po',
+ 'fields': [
+ {'label': 'PO', 'fieldname': 'po', 'fieldtype': 'Link', 'options': 'Purchase Order'},
+ {'label': 'Supplier', 'fieldname': 'supplier', 'fieldtype': 'Data', "fetch_from": "po.supplier"}
+ ],
+ 'permissions': [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "read": 1,
+ "role": "Supplier"
+ }
+ ]
+ }).insert(ignore_if_duplicate = True)
+
+def create_webform():
+ frappe.get_doc({
+ 'doctype': 'Web Form',
+ 'module': 'Buying',
+ 'title': 'SO Schedule',
+ 'route': 'so-schedule',
+ 'doc_type': 'Order Assignment',
+ 'web_form_fields': [
+ {
+ 'doctype': 'Web Form Field',
+ 'fieldname': 'po',
+ 'fieldtype': 'Link',
+ 'options': 'Purchase Order',
+ 'label': 'PO'
+ },
+ {
+ 'doctype': 'Web Form Field',
+ 'fieldname': 'supplier',
+ 'fieldtype': 'Data',
+ 'label': 'Supplier'
+ }
+ ]
+
+ }).insert(ignore_if_duplicate = True)
+
+def create_order_assignment(supplier, po):
+ frappe.get_doc({
+ 'doctype': 'Order Assignment',
+ 'po': po,
+ 'supplier': supplier,
+ }).insert(ignore_if_duplicate = True)
\ No newline at end of file
diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py
index 881f286baeb..3ce68d89bcd 100644
--- a/erpnext/tests/test_woocommerce.py
+++ b/erpnext/tests/test_woocommerce.py
@@ -12,12 +12,6 @@ from erpnext.erpnext_integrations.connectors.woocommerce_connection import order
class TestWoocommerce(unittest.TestCase):
def setUp(self):
- if not frappe.db.exists('Company', 'Woocommerce'):
- company = frappe.new_doc("Company")
- company.company_name = "Woocommerce"
- company.abbr = "W"
- company.default_currency = "INR"
- company.save()
woo_settings = frappe.get_doc("Woocommerce Settings")
if not woo_settings.secret:
@@ -26,14 +20,14 @@ class TestWoocommerce(unittest.TestCase):
woo_settings.api_consumer_key = "ck_fd43ff5756a6abafd95fadb6677100ce95a758a1"
woo_settings.api_consumer_secret = "cs_94360a1ad7bef7fa420a40cf284f7b3e0788454e"
woo_settings.enable_sync = 1
- woo_settings.company = "Woocommerce"
- woo_settings.tax_account = "Sales Expenses - W"
- woo_settings.f_n_f_account = "Expenses - W"
+ woo_settings.company = "_Test Company"
+ woo_settings.tax_account = "Sales Expenses - _TC"
+ woo_settings.f_n_f_account = "Expenses - _TC"
woo_settings.creation_user = "Administrator"
woo_settings.save(ignore_permissions=True)
def test_sales_order_for_woocommerce(self):
- frappe.flags.woocomm_test_order_data = {"id":75,"parent_id":0,"number":"74","order_key":"wc_order_5aa1281c2dacb","created_via":"checkout","version":"3.3.3","status":"processing","currency":"INR","date_created":"2018-03-08T12:10:04","date_created_gmt":"2018-03-08T12:10:04","date_modified":"2018-03-08T12:10:04","date_modified_gmt":"2018-03-08T12:10:04","discount_total":"0.00","discount_tax":"0.00","shipping_total":"150.00","shipping_tax":"0.00","cart_tax":"0.00","total":"649.00","total_tax":"0.00","prices_include_tax":False,"customer_id":12,"customer_ip_address":"103.54.99.5","customer_user_agent":"mozilla\\/5.0 (x11; linux x86_64) applewebkit\\/537.36 (khtml, like gecko) chrome\\/64.0.3282.186 safari\\/537.36","customer_note":"","billing":{"first_name":"Tony","last_name":"Stark","company":"Woocommerce","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN","email":"tony@gmail.com","phone":"123457890"},"shipping":{"first_name":"Tony","last_name":"Stark","company":"","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN"},"payment_method":"cod","payment_method_title":"Cash on delivery","transaction_id":"","date_paid":"","date_paid_gmt":"","date_completed":"","date_completed_gmt":"","cart_hash":"8e76b020d5790066496f244860c4703f","meta_data":[],"line_items":[{"id":80,"name":"Marvel","product_id":56,"variation_id":0,"quantity":1,"tax_class":"","subtotal":"499.00","subtotal_tax":"0.00","total":"499.00","total_tax":"0.00","taxes":[],"meta_data":[],"sku":"","price":499}],"tax_lines":[],"shipping_lines":[{"id":81,"method_title":"Flat rate","method_id":"flat_rate:1","total":"150.00","total_tax":"0.00","taxes":[],"meta_data":[{"id":623,"key":"Items","value":"Marvel × 1"}]}],"fee_lines":[],"coupon_lines":[],"refunds":[]}
+ frappe.flags.woocomm_test_order_data = {"id":75,"parent_id":0,"number":"74","order_key":"wc_order_5aa1281c2dacb","created_via":"checkout","version":"3.3.3","status":"processing","currency":"INR","date_created":"2018-03-08T12:10:04","date_created_gmt":"2018-03-08T12:10:04","date_modified":"2018-03-08T12:10:04","date_modified_gmt":"2018-03-08T12:10:04","discount_total":"0.00","discount_tax":"0.00","shipping_total":"150.00","shipping_tax":"0.00","cart_tax":"0.00","total":"649.00","total_tax":"0.00","prices_include_tax":False,"customer_id":12,"customer_ip_address":"103.54.99.5","customer_user_agent":"mozilla\\/5.0 (x11; linux x86_64) applewebkit\\/537.36 (khtml, like gecko) chrome\\/64.0.3282.186 safari\\/537.36","customer_note":"","billing":{"first_name":"Tony","last_name":"Stark","company":"_Test Company","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN","email":"tony@gmail.com","phone":"123457890"},"shipping":{"first_name":"Tony","last_name":"Stark","company":"","address_1":"Mumbai","address_2":"","city":"Dadar","state":"MH","postcode":"123","country":"IN"},"payment_method":"cod","payment_method_title":"Cash on delivery","transaction_id":"","date_paid":"","date_paid_gmt":"","date_completed":"","date_completed_gmt":"","cart_hash":"8e76b020d5790066496f244860c4703f","meta_data":[],"line_items":[{"id":80,"name":"Marvel","product_id":56,"variation_id":0,"quantity":1,"tax_class":"","subtotal":"499.00","subtotal_tax":"0.00","total":"499.00","total_tax":"0.00","taxes":[],"meta_data":[],"sku":"","price":499}],"tax_lines":[],"shipping_lines":[{"id":81,"method_title":"Flat rate","method_id":"flat_rate:1","total":"150.00","total_tax":"0.00","taxes":[],"meta_data":[{"id":623,"key":"Items","value":"Marvel × 1"}]}],"fee_lines":[],"coupon_lines":[],"refunds":[]}
order()
self.assertTrue(frappe.get_value("Customer",{"woocommerce_email":"tony@gmail.com"}))
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 76c7608c91f..9c8c371e051 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -7,6 +7,8 @@ def create_employee_records():
create_company()
create_missing_designation()
+ frappe.db.sql("DELETE FROM tabEmployee WHERE company='Test Org Chart'")
+
emp1 = create_employee('Test Employee 1', 'CEO')
emp2 = create_employee('Test Employee 2', 'CTO')
emp3 = create_employee('Test Employee 3', 'Head of Marketing and Sales', emp1)
diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py
index 2156bd51a4a..91df5480e35 100644
--- a/erpnext/tests/utils.py
+++ b/erpnext/tests/utils.py
@@ -2,9 +2,30 @@
# License: GNU General Public License v3. See license.txt
import copy
+import unittest
from contextlib import contextmanager
+from typing import Any, Dict, NewType, Optional
import frappe
+from frappe.core.doctype.report.report import get_report_module_dotted_path
+
+ReportFilters = Dict[str, Any]
+ReportName = NewType("ReportName", str)
+
+
+class ERPNextTestCase(unittest.TestCase):
+ """A sane default test class for ERPNext tests."""
+
+
+ @classmethod
+ def setUpClass(cls) -> None:
+ frappe.db.commit()
+ return super().setUpClass()
+
+ @classmethod
+ def tearDownClass(cls) -> None:
+ frappe.db.rollback()
+ return super().tearDownClass()
def create_test_contact_and_address():
@@ -78,3 +99,39 @@ def change_settings(doctype, settings_dict):
for key, value in previous_settings.items():
setattr(settings, key, value)
settings.save()
+
+
+def execute_script_report(
+ report_name: ReportName,
+ module: str,
+ filters: ReportFilters,
+ default_filters: Optional[ReportFilters] = None,
+ optional_filters: Optional[ReportFilters] = None
+ ):
+ """Util for testing execution of a report with specified filters.
+
+ Tests the execution of report with default_filters + filters.
+ Tests the execution using optional_filters one at a time.
+
+ Args:
+ report_name: Human readable name of report (unscrubbed)
+ module: module to which report belongs to
+ filters: specific values for filters
+ default_filters: default values for filters such as company name.
+ optional_filters: filters which should be tested one at a time in addition to default filters.
+ """
+
+ if default_filters is None:
+ default_filters = {}
+
+ report_execute_fn = frappe.get_attr(get_report_module_dotted_path(module, report_name) + ".execute")
+ report_filters = frappe._dict(default_filters).copy().update(filters)
+
+ report_data = report_execute_fn(report_filters)
+
+ if optional_filters:
+ for key, value in optional_filters.items():
+ filter_with_optional_param = report_filters.copy().update({key: value})
+ report_execute_fn(filter_with_optional_param)
+
+ return report_data
diff --git a/erpnext/utilities/workspace/utilities/utilities.json b/erpnext/utilities/workspace/utilities/utilities.json
index 4ad4afb8f41..02a8af5d6c9 100644
--- a/erpnext/utilities/workspace/utilities/utilities.json
+++ b/erpnext/utilities/workspace/utilities/utilities.json
@@ -1,19 +1,12 @@
{
- "category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Video\", \"col\": 4}}]",
"creation": "2020-09-10 12:21:22.335307",
- "developer_mode_only": 0,
- "disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
- "extends": "",
- "extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"idx": 0,
- "is_default": 0,
- "is_standard": 0,
"label": "Utilities",
"links": [
{
@@ -47,15 +40,12 @@
"type": "Link"
}
],
- "modified": "2021-08-05 12:16:03.350804",
+ "modified": "2021-08-05 12:16:03.350805",
"modified_by": "Administrator",
"module": "Utilities",
"name": "Utilities",
- "onboarding": "",
"owner": "user@erpnext.com",
"parent_page": "",
- "pin_to_bottom": 0,
- "pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index 7c18ecc41fe..a7838eebc14 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -98,14 +98,14 @@
{% for attr_value in attribute.item_attribute_values %}
-
+
- {{ attr_value.attribute_value }}
+ {{ attr_value }}
{% endfor %}
diff --git a/erpnext/www/all-products/index.py b/erpnext/www/all-products/index.py
index 335c10443a7..df5258b238c 100644
--- a/erpnext/www/all-products/index.py
+++ b/erpnext/www/all-products/index.py
@@ -27,7 +27,7 @@ def get_context(context):
filter_engine = ProductFiltersBuilder()
context.field_filters = filter_engine.get_field_filters()
- context.attribute_filters = filter_engine.get_attribute_fitlers()
+ context.attribute_filters = filter_engine.get_attribute_filters()
context.product_settings = product_settings
context.body_class = "product-page"
diff --git a/package.json b/package.json
index 5bc1e56a210..6c11e9dddc7 100644
--- a/package.json
+++ b/package.json
@@ -11,16 +11,9 @@
"bugs": {
"url": "https://github.com/frappe/erpnext/issues"
},
- "devDependencies": {
- "snyk": "^1.518.0"
- },
+ "devDependencies": {},
"dependencies": {
- "onscan.js": "^1.5.2",
- "html2canvas": "^1.1.4"
- },
- "scripts": {
- "snyk-protect": "snyk protect",
- "prepare": "yarn run snyk-protect"
- },
- "snyk": true
+ "html2canvas": "^1.1.4",
+ "onscan.js": "^1.5.2"
+ }
}
diff --git a/yarn.lock b/yarn.lock
index 0a49c52f0e8..8e5d1bd1c17 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,1006 +2,11 @@
# yarn lockfile v1
-"@arcanis/slice-ansi@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@arcanis/slice-ansi/-/slice-ansi-1.0.2.tgz#35331e41a1062e3c53c01ad2ec1555c5c1959d8f"
- integrity sha512-lDL63z0W/L/WTgqrwVOuNyMAsTv+pvjybd21z9SWdStmQoXT59E/iVWwat3gYjcdTNBf6oHAMoyFm8dtjpXEYw==
- dependencies:
- grapheme-splitter "^1.0.4"
-
-"@deepcode/dcignore@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@deepcode/dcignore/-/dcignore-1.0.2.tgz#39e4a3df7dde8811925330506e4bb3fbf3c288d8"
- integrity sha512-DPgxtHuJwBORpqRkPXzzOT+uoPRVJmaN7LR+pmeL6DQM90kj6G6GFUH1i/YpRH8NbML8ZGEDwB9f9u4UwD2pzg==
-
-"@nodelib/fs.scandir@2.1.4":
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
- integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==
- dependencies:
- "@nodelib/fs.stat" "2.0.4"
- run-parallel "^1.1.9"
-
-"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655"
- integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==
-
-"@nodelib/fs.walk@^1.2.3":
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063"
- integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==
- dependencies:
- "@nodelib/fs.scandir" "2.1.4"
- fastq "^1.6.0"
-
-"@octetstream/promisify@2.0.2":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@octetstream/promisify/-/promisify-2.0.2.tgz#29ac3bd7aefba646db670227f895d812c1a19615"
- integrity sha512-7XHoRB61hxsz8lBQrjC1tq/3OEIgpvGWg6DKAdwi7WRzruwkmsdwmOoUXbU4Dtd4RSOMDwed0SkP3y8UlMt1Bg==
-
-"@open-policy-agent/opa-wasm@^1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@open-policy-agent/opa-wasm/-/opa-wasm-1.2.0.tgz#481b766093f70b00efefbee1e4192f375fd34ca2"
- integrity sha512-CtUBTnzvDrT0NASa8IuGQTxFGgt2vxbLnMYuTA+uDFxOcA4uK4mGFgrhHJtxUZnWHiwemOvKKSY3BMCo7qiAsQ==
- dependencies:
- sprintf-js "^1.1.2"
- utf8 "^3.0.0"
-
-"@sindresorhus/is@^0.14.0":
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
- integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
-
-"@sindresorhus/is@^2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1"
- integrity sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==
-
-"@sindresorhus/is@^4.0.0":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.1.tgz#d26729db850fa327b7cacc5522252194404226f5"
- integrity sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==
-
-"@snyk/cli-interface@2.11.0", "@snyk/cli-interface@^2.11.0", "@snyk/cli-interface@^2.9.1", "@snyk/cli-interface@^2.9.2":
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/@snyk/cli-interface/-/cli-interface-2.11.0.tgz#9df68c8cd54de5dff69f0ab797a188541d9c8965"
- integrity sha512-T3xfDqrEFKclHGdJx4/5+D5F7e76/99f33guE4RTlVITBhy7VVnjz4t/NDr3UYqcC0MgAmiC4bSVYHnlshuwJw==
- dependencies:
- "@types/graphlib" "^2"
-
-"@snyk/cli-interface@^2.0.3":
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/@snyk/cli-interface/-/cli-interface-2.3.1.tgz#73f2f4bd717b9f03f096ede3ff5830eb8d2f3716"
- integrity sha512-JZvsmhDXSyjv1dkc12lPI3tNTNYlIaOiIQMYFg2RgqF3QmWjTyBUgRZcF7LoKyufHtS4dIudM6k1aHBpSaDrhw==
- dependencies:
- tslib "^1.9.3"
-
-"@snyk/cloud-config-parser@^1.9.2":
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/@snyk/cloud-config-parser/-/cloud-config-parser-1.9.2.tgz#e6c8e575db8527b33cf1ba766f86e1b3414cf6e1"
- integrity sha512-m8Y2+3l4fxj96QMrTfiCEaXgCpDkCkJIX/5wv0V0RHuxpUiyh+KxC2yJ8Su4wybBj6v6hB9hB7h5/L+Gy4V4PA==
- dependencies:
- esprima "^4.0.1"
- tslib "^1.10.0"
- yaml-js "^0.3.0"
-
-"@snyk/cocoapods-lockfile-parser@3.6.2":
- version "3.6.2"
- resolved "https://registry.yarnpkg.com/@snyk/cocoapods-lockfile-parser/-/cocoapods-lockfile-parser-3.6.2.tgz#803ae9466f408c48ba7c5a8ec51b9dbac6f633b3"
- integrity sha512-ca2JKOnSRzYHJkhOB9gYmdRZHmd02b/uBd/S0D5W+L9nIMS7sUBV5jfhKwVgrYPIpVNIc0XCI9rxK4TfkQRpiA==
- dependencies:
- "@snyk/dep-graph" "^1.23.1"
- "@types/js-yaml" "^3.12.1"
- js-yaml "^3.13.1"
- tslib "^1.10.0"
-
-"@snyk/code-client@3.4.1":
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/@snyk/code-client/-/code-client-3.4.1.tgz#b9d025897cd586e0aef903162ac0407d0bffc3cd"
- integrity sha512-XJ7tUdX1iQyzN/BmHac7p+Oyw1SyTcqSkCNExwBJxyQdlnUAKK6QKIWLXS81tTpZ79FgCdT+0fdS0AjsyS99eA==
- dependencies:
- "@deepcode/dcignore" "^1.0.2"
- "@snyk/fast-glob" "^3.2.6-patch"
- "@types/flat-cache" "^2.0.0"
- "@types/lodash.chunk" "^4.2.6"
- "@types/lodash.omit" "^4.5.6"
- "@types/lodash.union" "^4.6.6"
- "@types/micromatch" "^4.0.1"
- "@types/sarif" "^2.1.3"
- "@types/uuid" "^8.3.0"
- axios "^0.21.1"
- ignore "^5.1.8"
- lodash.chunk "^4.2.0"
- lodash.omit "^4.5.0"
- lodash.union "^4.6.0"
- micromatch "^4.0.2"
- queue "^6.0.1"
- uuid "^8.3.2"
-
-"@snyk/composer-lockfile-parser@^1.4.1":
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/@snyk/composer-lockfile-parser/-/composer-lockfile-parser-1.4.1.tgz#2f7c93ad367520322b16d9490a208fec08445e0e"
- integrity sha512-wNANv235j95NFsQuODIXCiQZ9kcyg9fz92Kg1zoGvaP3kN/ma7fgCnvQL/dyml6iouQJR5aZovjhrrfEFoKtiQ==
- dependencies:
- lodash.findkey "^4.6.0"
- lodash.get "^4.4.2"
- lodash.invert "^4.3.0"
- lodash.isempty "^4.4.0"
-
-"@snyk/dep-graph@^1.19.3", "@snyk/dep-graph@^1.21.0", "@snyk/dep-graph@^1.23.0", "@snyk/dep-graph@^1.23.1", "@snyk/dep-graph@^1.27.1", "@snyk/dep-graph@^1.28.0":
- version "1.28.0"
- resolved "https://registry.yarnpkg.com/@snyk/dep-graph/-/dep-graph-1.28.0.tgz#d68c0576cb3562c6e819ca8a8c7ac29ee11d9776"
- integrity sha512-Oup9nAvb558jdNvbZah/vaBtOtCcizkdeS+OBQeBIqIffyer4mc4juSn4b1SFjCpu7AG7piio8Lj8k1B9ps6Tg==
- dependencies:
- event-loop-spinner "^2.1.0"
- lodash.clone "^4.5.0"
- lodash.constant "^3.0.0"
- lodash.filter "^4.6.0"
- lodash.foreach "^4.5.0"
- lodash.isempty "^4.4.0"
- lodash.isequal "^4.5.0"
- lodash.isfunction "^3.0.9"
- lodash.isundefined "^3.0.1"
- lodash.keys "^4.2.0"
- lodash.map "^4.6.0"
- lodash.reduce "^4.6.0"
- lodash.size "^4.2.0"
- lodash.transform "^4.6.0"
- lodash.union "^4.6.0"
- lodash.values "^4.3.0"
- object-hash "^2.0.3"
- semver "^7.0.0"
- tslib "^1.13.0"
-
-"@snyk/docker-registry-v2-client@1.13.9":
- version "1.13.9"
- resolved "https://registry.yarnpkg.com/@snyk/docker-registry-v2-client/-/docker-registry-v2-client-1.13.9.tgz#54c2e3071de58fc6fc12c5fef5eaeae174ecda12"
- integrity sha512-DIFLEhr8m1GrAwsLGInJmpcQMacjuhf3jcbpQTR+LeMvZA9IuKq+B7kqw2O2FzMiHMZmUb5z+tV+BR7+IUHkFQ==
- dependencies:
- needle "^2.5.0"
- parse-link-header "^1.0.1"
- tslib "^1.10.0"
-
-"@snyk/fast-glob@^3.2.6-patch":
- version "3.2.6-patch"
- resolved "https://registry.yarnpkg.com/@snyk/fast-glob/-/fast-glob-3.2.6-patch.tgz#a0866bedb17f95255e4050dad08daeaff0f4caa8"
- integrity sha512-E/Pfdze/WFfxwyuTFcfhQN1SwyUsc43yuCoW63RVBCaxTD6OzhVD2Pvc/Sy7BjiWUfmelzyKkIBpoow8zZX7Zg==
- dependencies:
- "@nodelib/fs.stat" "^2.0.2"
- "@nodelib/fs.walk" "^1.2.3"
- "@snyk/glob-parent" "^5.1.2-patch.1"
- merge2 "^1.3.0"
- micromatch "^4.0.2"
- picomatch "^2.2.1"
-
-"@snyk/fix@1.554.0":
- version "1.554.0"
- resolved "https://registry.yarnpkg.com/@snyk/fix/-/fix-1.554.0.tgz#7ae786882e0ffea5e7f10d0b41e3d593b65555c4"
- integrity sha512-q2eRVStgspPeI2wZ2EQGLpiWZMRg7o+4tsCk6m/kHZgQGDN4Bb7L3xslFW3OgF0+ZksYSaHl2cW2HmGiLRaYcA==
- dependencies:
- "@snyk/dep-graph" "^1.21.0"
- chalk "4.1.0"
- debug "^4.3.1"
- ora "5.3.0"
- p-map "^4.0.0"
- strip-ansi "6.0.0"
-
-"@snyk/gemfile@1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@snyk/gemfile/-/gemfile-1.2.0.tgz#919857944973cce74c650e5428aaf11bcd5c0457"
- integrity sha512-nI7ELxukf7pT4/VraL4iabtNNMz8mUo7EXlqCFld8O5z6mIMLX9llps24iPpaIZOwArkY3FWA+4t+ixyvtTSIA==
-
-"@snyk/glob-parent@^5.1.2-patch.1":
- version "5.1.2-patch.1"
- resolved "https://registry.yarnpkg.com/@snyk/glob-parent/-/glob-parent-5.1.2-patch.1.tgz#87733b4ab282043fa7915200bc94cb391df6d44f"
- integrity sha512-OkUPdHgxIWKAAzceG1nraNA0kgI+eS0I9wph8tll9UL0slD2mIWSj4mAqroGovaEXm8nHedoUfuDRGEb6wnzCQ==
- dependencies:
- is-glob "^4.0.1"
-
-"@snyk/graphlib@2.1.9-patch.3", "@snyk/graphlib@^2.1.9-patch.3":
- version "2.1.9-patch.3"
- resolved "https://registry.yarnpkg.com/@snyk/graphlib/-/graphlib-2.1.9-patch.3.tgz#b8edb2335af1978db7f3cb1f28f5d562960acf23"
- integrity sha512-bBY9b9ulfLj0v2Eer0yFYa3syVeIxVKl2EpxSrsVeT4mjA0CltZyHsF0JjoaGXP27nItTdJS5uVsj1NA+3aE+Q==
- dependencies:
- lodash.clone "^4.5.0"
- lodash.constant "^3.0.0"
- lodash.filter "^4.6.0"
- lodash.foreach "^4.5.0"
- lodash.has "^4.5.2"
- lodash.isempty "^4.4.0"
- lodash.isfunction "^3.0.9"
- lodash.isundefined "^3.0.1"
- lodash.keys "^4.2.0"
- lodash.map "^4.6.0"
- lodash.reduce "^4.6.0"
- lodash.size "^4.2.0"
- lodash.transform "^4.6.0"
- lodash.union "^4.6.0"
- lodash.values "^4.3.0"
-
-"@snyk/inquirer@^7.3.3-patch":
- version "7.3.3-patch"
- resolved "https://registry.yarnpkg.com/@snyk/inquirer/-/inquirer-7.3.3-patch.tgz#ef84d531724c53b755e8dd454e1a3c2ccdcfc0bf"
- integrity sha512-aWiQSOacH2lOpJ1ard9ErABcH4tdJogdr+mg1U67iZJOPO9n2gFgAwz1TQJDyPkv4/A5mh4hT2rg03Uq+KBn2Q==
- dependencies:
- ansi-escapes "^4.2.1"
- chalk "^4.1.0"
- cli-cursor "^3.1.0"
- cli-width "^3.0.0"
- external-editor "^3.0.3"
- figures "^3.0.0"
- lodash.assign "^4.2.0"
- lodash.assignin "^4.2.0"
- lodash.clone "^4.5.0"
- lodash.defaults "^4.2.0"
- lodash.filter "^4.6.0"
- lodash.find "^4.6.0"
- lodash.findindex "^4.6.0"
- lodash.flatten "^4.4.0"
- lodash.isboolean "^3.0.3"
- lodash.isfunction "^3.0.9"
- lodash.isnumber "^3.0.3"
- lodash.isplainobject "^4.0.6"
- lodash.isstring "^4.0.1"
- lodash.last "^3.0.0"
- lodash.map "^4.6.0"
- lodash.omit "^4.5.0"
- lodash.set "^4.3.2"
- lodash.sum "^4.0.2"
- lodash.uniq "^4.5.0"
- mute-stream "0.0.8"
- run-async "^2.4.0"
- rxjs "^6.6.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
- through "^2.3.6"
-
-"@snyk/java-call-graph-builder@1.19.1":
- version "1.19.1"
- resolved "https://registry.yarnpkg.com/@snyk/java-call-graph-builder/-/java-call-graph-builder-1.19.1.tgz#1d579d782df3bb5f9d5171cc35180596cd90aa8b"
- integrity sha512-bxjHef5Qm3pNc+BrFlxMudmSSbOjA395ZqBddc+dvsFHoHeyNbiY56Y1JSGUlTgjRM+PKNPBiCuELTSMaROeZg==
- dependencies:
- "@snyk/graphlib" "2.1.9-patch.3"
- ci-info "^2.0.0"
- debug "^4.1.1"
- glob "^7.1.6"
- jszip "^3.2.2"
- needle "^2.3.3"
- progress "^2.0.3"
- snyk-config "^4.0.0-rc.2"
- source-map-support "^0.5.7"
- temp-dir "^2.0.0"
- tmp "^0.2.1"
- tslib "^1.9.3"
- xml-js "^1.6.11"
-
-"@snyk/java-call-graph-builder@1.20.0":
- version "1.20.0"
- resolved "https://registry.yarnpkg.com/@snyk/java-call-graph-builder/-/java-call-graph-builder-1.20.0.tgz#ffca734cf7ce276a69277963149358190eaac3e5"
- integrity sha512-NX8bpIu7oG5cuSSm6WvtxqcCuJs2gRjtKhtuSeF1p5TYXyESs3FXQ0nHjfY90LiyTTc+PW/UBq6SKbBA6bCBww==
- dependencies:
- "@snyk/graphlib" "2.1.9-patch.3"
- ci-info "^2.0.0"
- debug "^4.1.1"
- glob "^7.1.6"
- jszip "^3.2.2"
- needle "^2.3.3"
- progress "^2.0.3"
- snyk-config "^4.0.0-rc.2"
- source-map-support "^0.5.7"
- temp-dir "^2.0.0"
- tmp "^0.2.1"
- tslib "^1.9.3"
- xml-js "^1.6.11"
-
-"@snyk/mix-parser@^1.1.1":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@snyk/mix-parser/-/mix-parser-1.3.2.tgz#930de1d9c3a91e20660751f78c3e6f6a88ac5b2b"
- integrity sha512-0Aq9vcgmjH0d9Gk5q0k6l4ZOvSHPf6/BCQGDVOpKp0hwOkXWnpDOLLPxL+uBCktuH9zTYQFB0aTk91kQImZqmA==
- dependencies:
- "@snyk/dep-graph" "^1.28.0"
- tslib "^2.0.0"
-
-"@snyk/rpm-parser@^2.0.0":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@snyk/rpm-parser/-/rpm-parser-2.2.1.tgz#b61ccf5478684b203576bd2be68de434ccbb0069"
- integrity sha512-OAON0bPf3c5fgM/GK9DX0aZErB6SnuRyYlPH0rqI1TXGsKrYnVELhaE6ctNbEfPTQuY9r6q0vM+UYDaFM/YliA==
- dependencies:
- event-loop-spinner "^2.0.0"
-
-"@snyk/snyk-cocoapods-plugin@2.5.2":
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/@snyk/snyk-cocoapods-plugin/-/snyk-cocoapods-plugin-2.5.2.tgz#cd724fcd637cb3af76187bf7254819b6079489f6"
- integrity sha512-WHhnwyoGOhjFOjBXqUfszD84SErrtjHjium/4xFbqKpEE+yuwxs8OwV/S29BtxhYiGtjpD1azv5QtH30VUMl0A==
- dependencies:
- "@snyk/cli-interface" "^2.11.0"
- "@snyk/cocoapods-lockfile-parser" "3.6.2"
- "@snyk/dep-graph" "^1.23.1"
- source-map-support "^0.5.7"
- tslib "^2.0.0"
-
-"@snyk/snyk-docker-pull@3.2.3":
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/@snyk/snyk-docker-pull/-/snyk-docker-pull-3.2.3.tgz#9743ea624098c7abd0f95c438c76067530494f4b"
- integrity sha512-hiFiSmWGLc2tOI7FfgIhVdFzO2f69im8O6p3OV4xEZ/Ss1l58vwtqudItoswsk7wj/azRlgfBW8wGu2MjoudQg==
- dependencies:
- "@snyk/docker-registry-v2-client" "1.13.9"
- child-process "^1.0.2"
- tar-stream "^2.1.2"
- tmp "^0.1.0"
-
-"@snyk/snyk-hex-plugin@1.1.4":
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/@snyk/snyk-hex-plugin/-/snyk-hex-plugin-1.1.4.tgz#4a5b1684cecc1a557ec1a9f5f8646683ae89f0da"
- integrity sha512-kLfFGckSmyKe667UGPyWzR/H7/Trkt4fD8O/ktElOx1zWgmivpLm0Symb4RCfEmz9irWv+N6zIKRrfSNdytcPQ==
- dependencies:
- "@snyk/dep-graph" "^1.28.0"
- "@snyk/mix-parser" "^1.1.1"
- debug "^4.3.1"
- tmp "^0.0.33"
- tslib "^2.0.0"
- upath "2.0.1"
-
-"@szmarczak/http-timer@^1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
- integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
- dependencies:
- defer-to-connect "^1.0.1"
-
-"@szmarczak/http-timer@^4.0.5":
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
- integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
- dependencies:
- defer-to-connect "^2.0.0"
-
-"@types/braces@*":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb"
- integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==
-
-"@types/cacheable-request@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
- integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
- dependencies:
- "@types/http-cache-semantics" "*"
- "@types/keyv" "*"
- "@types/node" "*"
- "@types/responselike" "*"
-
-"@types/debug@^4.1.4":
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
- integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
-
-"@types/emscripten@^1.38.0":
- version "1.39.4"
- resolved "https://registry.yarnpkg.com/@types/emscripten/-/emscripten-1.39.4.tgz#d61990c0cee72c4e475de737a140b51fe925a2c8"
- integrity sha512-k3LLVMFrdNA9UCvMDPWMbFrGPNb+GcPyw29ktJTo1RCN7RmxFG5XzPZcPKRlnLuLT/FRm8wp4ohvDwNY7GlROQ==
-
-"@types/flat-cache@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@types/flat-cache/-/flat-cache-2.0.0.tgz#64e5d3b426c392b603a208a55bdcc7d920ce6e57"
- integrity sha512-fHeEsm9hvmZ+QHpw6Fkvf19KIhuqnYLU6vtWLjd5BsMd/qVi7iTkMioDZl0mQmfNRA1A6NwvhrSRNr9hGYZGww==
-
-"@types/graphlib@^2":
- version "2.1.7"
- resolved "https://registry.yarnpkg.com/@types/graphlib/-/graphlib-2.1.7.tgz#e6a47a4f43511f5bad30058a669ce5ce93bfd823"
- integrity sha512-K7T1n6U2HbTYu+SFHlBjz/RH74OA2D/zF1qlzn8uXbvB4uRg7knOM85ugS2bbXI1TXMh7rLqk4OVRwIwEBaixg==
-
-"@types/http-cache-semantics@*":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
- integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
-
-"@types/js-yaml@^3.12.1":
- version "3.12.2"
- resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.2.tgz#a35a1809c33a68200fb6403d1ad708363c56470a"
- integrity sha512-0CFu/g4mDSNkodVwWijdlr8jH7RoplRWNgovjFLEZeT+QEbbZXjBmCe3HwaWheAlCbHwomTwzZoSedeOycABug==
-
-"@types/keyv@*":
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
- integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
- dependencies:
- "@types/node" "*"
-
-"@types/lodash.chunk@^4.2.6":
- version "4.2.6"
- resolved "https://registry.yarnpkg.com/@types/lodash.chunk/-/lodash.chunk-4.2.6.tgz#9d35f05360b0298715d7f3d9efb34dd4f77e5d2a"
- integrity sha512-SPlusB7jxXyGcTXYcUdWr7WmhArO/rmTq54VN88iKMxGUhyg79I4Q8n4riGn3kjaTjOJrVlHhxgX/d7woak5BQ==
- dependencies:
- "@types/lodash" "*"
-
-"@types/lodash.omit@^4.5.6":
- version "4.5.6"
- resolved "https://registry.yarnpkg.com/@types/lodash.omit/-/lodash.omit-4.5.6.tgz#f2a9518259e481a48ff7ec423420fa8fd58933e2"
- integrity sha512-KXPpOSNX2h0DAG2w7ajpk7TXvWF28ZHs5nJhOJyP0BQHkehgr948RVsToItMme6oi0XJkp19CbuNXkIX8FiBlQ==
- dependencies:
- "@types/lodash" "*"
-
-"@types/lodash.union@^4.6.6":
- version "4.6.6"
- resolved "https://registry.yarnpkg.com/@types/lodash.union/-/lodash.union-4.6.6.tgz#2f77f2088326ed147819e9e384182b99aae8d4b0"
- integrity sha512-Wu0ZEVNcyCz8eAn6TlUbYWZoGbH9E+iOHxAZbwUoCEXdUiy6qpcz5o44mMXViM4vlPLLCPlkAubEP1gokoSZaw==
- dependencies:
- "@types/lodash" "*"
-
-"@types/lodash@*":
- version "4.14.168"
- resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
- integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
-
-"@types/micromatch@^4.0.1":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.1.tgz#9381449dd659fc3823fd2a4190ceacc985083bc7"
- integrity sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw==
- dependencies:
- "@types/braces" "*"
-
-"@types/node@*":
- version "13.5.3"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.3.tgz#37f1f539b7535b9fb4ef77d59db1847a837b7f17"
- integrity sha512-ZPnWX9PW992w6DUsz3JIXHaSb5v7qmKCVzC3km6SxcDGxk7zmLfYaCJTbktIa5NeywJkkZDhGldKqDIvC5DRrA==
-
-"@types/node@^13.7.0":
- version "13.13.50"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.50.tgz#bc8ebf70c392a98ffdba7aab9b46989ea96c1c62"
- integrity sha512-y7kkh+hX/0jZNxMyBR/6asG0QMSaPSzgeVK63dhWHl4QAXCQB8lExXmzLL6SzmOgKHydtawpMnNhlDbv7DXPEA==
-
-"@types/responselike@*", "@types/responselike@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
- integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
- dependencies:
- "@types/node" "*"
-
-"@types/sarif@^2.1.3":
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/@types/sarif/-/sarif-2.1.3.tgz#1f9c16033f1461536ac014284920350109614c02"
- integrity sha512-zf+EoIplTkQW2TV2mwtJtlI0g540Z3Rs9tX9JqRAtyjnDCqkP+eMTgWCj3PGNbQpi+WXAjvC3Ou/dvvX2sLK4w==
-
-"@types/semver@^7.1.0":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
- integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
-
-"@types/treeify@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/treeify/-/treeify-1.0.0.tgz#f04743cb91fc38254e8585d692bd92503782011c"
- integrity sha512-ONpcZAEYlbPx4EtJwfTyCDQJGUpKf4sEcuySdCVjK5Fj/3vHp5HII1fqa1/+qrsLnpYELCQTfVW/awsGJePoIg==
-
-"@types/uuid@^8.3.0":
- version "8.3.0"
- resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
- integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
-
-"@yarnpkg/core@^2.4.0":
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/@yarnpkg/core/-/core-2.4.0.tgz#b5d8cc7ee2ddb022816c7afa3f83c3ee3d317c80"
- integrity sha512-FYjcPNTfDfMKLFafQPt49EY28jnYC82Z2S7oMwLPUh144BL8v8YXzb4aCnFyi5nFC5h2kcrJfZh7+Pm/qvCqGw==
- dependencies:
- "@arcanis/slice-ansi" "^1.0.2"
- "@types/semver" "^7.1.0"
- "@types/treeify" "^1.0.0"
- "@yarnpkg/fslib" "^2.4.0"
- "@yarnpkg/json-proxy" "^2.1.0"
- "@yarnpkg/libzip" "^2.2.1"
- "@yarnpkg/parsers" "^2.3.0"
- "@yarnpkg/pnp" "^2.3.2"
- "@yarnpkg/shell" "^2.4.1"
- binjumper "^0.1.4"
- camelcase "^5.3.1"
- chalk "^3.0.0"
- ci-info "^2.0.0"
- clipanion "^2.6.2"
- cross-spawn "7.0.3"
- diff "^4.0.1"
- globby "^11.0.1"
- got "^11.7.0"
- json-file-plus "^3.3.1"
- lodash "^4.17.15"
- micromatch "^4.0.2"
- mkdirp "^0.5.1"
- p-limit "^2.2.0"
- pluralize "^7.0.0"
- pretty-bytes "^5.1.0"
- semver "^7.1.2"
- stream-to-promise "^2.2.0"
- tar-stream "^2.0.1"
- treeify "^1.1.0"
- tslib "^1.13.0"
- tunnel "^0.0.6"
-
-"@yarnpkg/fslib@^2.1.0", "@yarnpkg/fslib@^2.4.0":
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/@yarnpkg/fslib/-/fslib-2.4.0.tgz#a265b737cd089ef293ad964e06c143f5efd411a9"
- integrity sha512-CwffYY9owtl3uImNOn1K4jl5iIb/L16a9UZ9Q3lkBARk6tlUsPrNFX00eoUlFcLn49TTfd3zdN6higloGCyncw==
- dependencies:
- "@yarnpkg/libzip" "^2.2.1"
- tslib "^1.13.0"
-
-"@yarnpkg/json-proxy@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@yarnpkg/json-proxy/-/json-proxy-2.1.0.tgz#362a161678cd7dda74b47b4fc848a2f1730d16cd"
- integrity sha512-rOgCg2DkyviLgr80mUMTt9vzdf5RGOujQB26yPiXjlz4WNePLBshKlTNG9rKSoKQSOYEQcw6cUmosfOKDatrCw==
- dependencies:
- "@yarnpkg/fslib" "^2.1.0"
- tslib "^1.13.0"
-
-"@yarnpkg/libzip@^2.2.1":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@yarnpkg/libzip/-/libzip-2.2.1.tgz#61c9b8b2499ee6bd9c4fcbf8248f68e07bd89948"
- integrity sha512-AYDJXrkzayoDd3ZlVgFJ+LyDX+Zj/cki3vxIpcYxejtgkl3aquVWOxlC0DD9WboBWsJFIP1MjrUbchLyh++/7A==
- dependencies:
- "@types/emscripten" "^1.38.0"
- tslib "^1.13.0"
-
-"@yarnpkg/lockfile@^1.1.0":
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
- integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
-
-"@yarnpkg/parsers@^2.3.0":
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/@yarnpkg/parsers/-/parsers-2.3.0.tgz#7b9564c6df02f4921d5cfe8287c4b648e93ea84b"
- integrity sha512-qgz0QUgOvnhtF92kaluIhIIKBUHlYlHUBQxqh5v9+sxEQvUeF6G6PKiFlzo3E6O99XwvNEGpVu1xZPoSGyGscQ==
- dependencies:
- js-yaml "^3.10.0"
- tslib "^1.13.0"
-
-"@yarnpkg/pnp@^2.3.2":
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/@yarnpkg/pnp/-/pnp-2.3.2.tgz#9a052a06bf09c9f0b7c31e0867a7e725cb6401ed"
- integrity sha512-JdwHu1WBCISqJEhIwx6Hbpe8MYsYbkGMxoxolkDiAeJ9IGEe08mQcbX1YmUDV1ozSWlm9JZE90nMylcDsXRFpA==
- dependencies:
- "@types/node" "^13.7.0"
- "@yarnpkg/fslib" "^2.4.0"
- tslib "^1.13.0"
-
-"@yarnpkg/shell@^2.4.1":
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/@yarnpkg/shell/-/shell-2.4.1.tgz#abc557f8924987c9c382703e897433a82780265d"
- integrity sha512-oNNJkH8ZI5uwu0dMkJf737yMSY1WXn9gp55DqSA5wAOhKvV5DJTXFETxkVgBQhO6Bow9tMGSpvowTMD/oAW/9g==
- dependencies:
- "@yarnpkg/fslib" "^2.4.0"
- "@yarnpkg/parsers" "^2.3.0"
- clipanion "^2.6.2"
- cross-spawn "7.0.3"
- fast-glob "^3.2.2"
- micromatch "^4.0.2"
- stream-buffers "^3.0.2"
- tslib "^1.13.0"
-
-abbrev@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
- integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
-
-aggregate-error@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
- integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
- dependencies:
- clean-stack "^2.0.0"
- indent-string "^4.0.0"
-
-ansi-align@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
- integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
- dependencies:
- string-width "^3.0.0"
-
-ansi-escapes@3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
- integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
-
-ansi-escapes@^4.2.1:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
- integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
- dependencies:
- type-fest "^0.21.3"
-
-ansi-regex@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
- integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
-
-ansi-regex@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
- integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-
-ansi-styles@^3.2.0, ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
- integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
- dependencies:
- color-convert "^2.0.1"
-
-ansicolors@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
- integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=
-
-any-promise@^1.1.0, any-promise@~1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
- integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
-
-archy@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
- integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
-
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
- dependencies:
- sprintf-js "~1.0.2"
-
-array-union@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
- integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
-asap@~2.0.3:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
- integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
-
-asn1@~0.2.0:
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
- integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
- dependencies:
- safer-buffer "~2.1.0"
-
-async@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
- integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
-
-axios@^0.21.1:
- version "0.21.1"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
- integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
- dependencies:
- follow-redirects "^1.10.0"
-
-balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
-
base64-arraybuffer@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45"
integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==
-base64-js@^1.3.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
- integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-
-bcrypt-pbkdf@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
- integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
- dependencies:
- tweetnacl "^0.14.3"
-
-binjumper@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/binjumper/-/binjumper-0.1.4.tgz#4acc0566832714bd6508af6d666bd9e5e21fc7f8"
- integrity sha512-Gdxhj+U295tIM6cO4bJO1jsvSjBVHNpj2o/OwW7pqDEtaqF6KdOxjtbo93jMMKAkP7+u09+bV8DhSqjIv4qR3w==
-
-bl@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.1.tgz#1cbb439299609e419b5a74d7fce2f8b37d8e5c6f"
- integrity sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==
- dependencies:
- readable-stream "^3.0.1"
-
-bl@^4.0.3:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
- integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
- dependencies:
- buffer "^5.5.0"
- inherits "^2.0.4"
- readable-stream "^3.4.0"
-
-boolean@^3.0.1:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.3.tgz#0fee0c9813b66bef25a8a6a904bb46736d05f024"
- integrity sha512-EqrTKXQX6Z3A2nRmMEIlAIfjQOgFnVO2nqZGpbcsPnYGWBwpFqzlrozU1dy+S2iqfYDLh26ef4KrgTxu9xQrxA==
-
-boxen@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
- integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
- dependencies:
- ansi-align "^3.0.0"
- camelcase "^5.3.1"
- chalk "^3.0.0"
- cli-boxes "^2.2.0"
- string-width "^4.1.0"
- term-size "^2.1.0"
- type-fest "^0.8.1"
- widest-line "^3.1.0"
-
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-braces@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
- integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
- dependencies:
- fill-range "^7.0.1"
-
-browserify-zlib@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
- integrity sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=
- dependencies:
- pako "~0.2.0"
-
-buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-buffer@^5.5.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
- integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
- dependencies:
- base64-js "^1.3.1"
- ieee754 "^1.1.13"
-
-cacheable-lookup@^5.0.3:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
- integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
-
-cacheable-request@^6.0.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
- integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^3.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^4.1.0"
- responselike "^1.0.2"
-
-cacheable-request@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
- integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^4.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^4.1.0"
- responselike "^2.0.0"
-
-call-bind@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
- integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
- dependencies:
- function-bind "^1.1.1"
- get-intrinsic "^1.0.2"
-
-camelcase@^5.3.1:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
- integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-
-chalk@4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
- integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
- integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chardet@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
- integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-
-child-process@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/child-process/-/child-process-1.0.2.tgz#98974dc7ed1ee4c6229f8e305fa7313a6885a7f2"
- integrity sha1-mJdNx+0e5MYin44wX6cxOmiFp/I=
-
-chownr@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
- integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
-
-ci-info@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
- integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
-cli-boxes@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
- integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
-
-cli-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
- integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
- dependencies:
- restore-cursor "^3.1.0"
-
-cli-spinner@0.2.10:
- version "0.2.10"
- resolved "https://registry.yarnpkg.com/cli-spinner/-/cli-spinner-0.2.10.tgz#f7d617a36f5c47a7bc6353c697fc9338ff782a47"
- integrity sha512-U0sSQ+JJvSLi1pAYuJykwiA8Dsr15uHEy85iCJ6A+0DjVxivr3d+N2Wjvodeg89uP5K6TswFkKBfAD7B3YSn/Q==
-
-cli-spinners@^2.5.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939"
- integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==
-
-cli-width@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
- integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
-
-clipanion@^2.6.2:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/clipanion/-/clipanion-2.6.2.tgz#820e7440812052442455b248f927b187ed732f71"
- integrity sha512-0tOHJNMF9+4R3qcbBL+4IxLErpaYSYvzs10aXuECDbZdJOuJHdagJMAqvLdeaUQTI/o2uSCDRpet6ywDiKOAYw==
-
-clone-response@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
- integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
- dependencies:
- mimic-response "^1.0.0"
-
-clone@^1.0.2:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
- integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
-
-color-convert@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
- dependencies:
- color-name "1.1.3"
-
-color-convert@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
- integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
- dependencies:
- color-name "~1.1.4"
-
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-
-color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-configstore@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
- integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
- dependencies:
- dot-prop "^5.2.0"
- graceful-fs "^4.1.2"
- make-dir "^3.0.0"
- unique-string "^2.0.0"
- write-file-atomic "^3.0.0"
- xdg-basedir "^4.0.0"
-
-core-js@^3.6.5:
- version "3.11.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926"
- integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw==
-
-core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
-
-cross-spawn@7.0.3:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
- integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-cross-spawn@^6.0.0:
- version "6.0.5"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
- integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
- dependencies:
- nice-try "^1.0.4"
- path-key "^2.0.1"
- semver "^5.5.0"
- shebang-command "^1.2.0"
- which "^1.2.9"
-
-crypto-random-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
- integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
-
css-line-break@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef"
@@ -1009,481 +14,6 @@ css-line-break@1.1.1:
dependencies:
base64-arraybuffer "^0.2.0"
-debug@^3.1.0, debug@^3.2.6:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
- integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
- dependencies:
- ms "^2.1.1"
-
-debug@^4.2.0, debug@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
- integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
- dependencies:
- ms "2.1.2"
-
-decompress-response@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
- integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
- dependencies:
- mimic-response "^1.0.0"
-
-decompress-response@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
- integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
- dependencies:
- mimic-response "^3.1.0"
-
-deep-extend@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
- integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-
-defaults@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
- integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
- dependencies:
- clone "^1.0.2"
-
-defer-to-connect@^1.0.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
- integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-
-defer-to-connect@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
- integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
-
-define-properties@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
- integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
- dependencies:
- object-keys "^1.0.12"
-
-detect-node@^2.0.4:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79"
- integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==
-
-diff@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
- integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-
-dir-glob@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
- integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
- dependencies:
- path-type "^4.0.0"
-
-docker-modem@2.1.3:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-2.1.3.tgz#15432225f63db02eb5de4bb9a621b7293e5f264d"
- integrity sha512-cwaRptBmYZwu/FyhGcqBm2MzXA77W2/E6eVkpOZVDk6PkI9Bjj84xPrXiHMA+OWjzNy+DFjgKh8Q+1hMR7/OHg==
- dependencies:
- debug "^4.1.1"
- readable-stream "^3.5.0"
- split-ca "^1.0.1"
- ssh2 "^0.8.7"
-
-dockerfile-ast@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/dockerfile-ast/-/dockerfile-ast-0.2.0.tgz#13cc4a6fe3aea30a4104622b30f49a0fe3a5c038"
- integrity sha512-iQyp12k1A4tF3sEfLAq2wfFPKdpoiGTJeuiu2Y1bdEqIZu0DfSSL2zm0fk7a/UHeQkngnYaRRGuON+C+2LO1Fw==
- dependencies:
- vscode-languageserver-types "^3.16.0"
-
-dot-prop@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb"
- integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==
- dependencies:
- is-obj "^2.0.0"
-
-dotnet-deps-parser@5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/dotnet-deps-parser/-/dotnet-deps-parser-5.0.0.tgz#5115c442cbefea59e4fb9f9ed8fa4863a0f3186d"
- integrity sha512-1l9K4UnQQHSfKgeHeLrxnB53AidCZqPyf9dkRL4/fZl8//NPiiDD43zHtgylw8DHlO7gvM8+O5a0UPHesNYZKw==
- dependencies:
- lodash.isempty "^4.4.0"
- lodash.set "^4.3.2"
- lodash.uniq "^4.5.0"
- source-map-support "^0.5.7"
- tslib "^1.10.0"
- xml2js "0.4.23"
-
-duplexer3@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
- integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
-
-duplexify@^3.5.0, duplexify@^3.6.0:
- version "3.7.1"
- resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
- integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
- dependencies:
- end-of-stream "^1.0.0"
- inherits "^2.0.1"
- readable-stream "^2.0.0"
- stream-shift "^1.0.0"
-
-elfy@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/elfy/-/elfy-1.0.0.tgz#7a1c86af7d41e0a568cbb4a3fa5b685648d9efcd"
- integrity sha512-4Kp3AA94jC085IJox+qnvrZ3PudqTi4gQNvIoTZfJJ9IqkRuCoqP60vCVYlIg00c5aYusi5Wjh2bf0cHYt+6gQ==
- dependencies:
- endian-reader "^0.3.0"
-
-email-validator@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed"
- integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==
-
-emoji-regex@^7.0.1:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
- integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
-
-emoji-regex@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
- integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-
-end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
- integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
- dependencies:
- once "^1.4.0"
-
-end-of-stream@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.1.0.tgz#e9353258baa9108965efc41cb0ef8ade2f3cfb07"
- integrity sha1-6TUyWLqpEIll78QcsO+K3i88+wc=
- dependencies:
- once "~1.3.0"
-
-endian-reader@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/endian-reader/-/endian-reader-0.3.0.tgz#84eca436b80aed0d0639c47291338b932efe50a0"
- integrity sha1-hOykNrgK7Q0GOcRykTOLky7+UKA=
-
-es6-error@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
- integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
-
-escape-goat@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
- integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
-
-escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-
-escape-string-regexp@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
- integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-
-esprima@^4.0.0, esprima@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
- integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
-event-loop-spinner@^2.0.0, event-loop-spinner@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/event-loop-spinner/-/event-loop-spinner-2.1.0.tgz#75f501d585105c6d57f174073b39af1b6b3a1567"
- integrity sha512-RJ10wL8/F9AlfBgRCvYctJIXSb9XkVmSCK3GGUvPD3dJrvTjDeDT0tmhcbEC6I2NEjNM9xD38HQJ4F/f/gb4VQ==
- dependencies:
- tslib "^2.1.0"
-
-execa@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
- integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
- dependencies:
- cross-spawn "^6.0.0"
- get-stream "^4.0.0"
- is-stream "^1.1.0"
- npm-run-path "^2.0.0"
- p-finally "^1.0.0"
- signal-exit "^3.0.0"
- strip-eof "^1.0.0"
-
-external-editor@^3.0.3:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
- integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
- dependencies:
- chardet "^0.7.0"
- iconv-lite "^0.4.24"
- tmp "^0.0.33"
-
-fast-glob@^3.1.1, fast-glob@^3.2.2:
- version "3.2.5"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661"
- integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==
- dependencies:
- "@nodelib/fs.stat" "^2.0.2"
- "@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.0"
- merge2 "^1.3.0"
- micromatch "^4.0.2"
- picomatch "^2.2.1"
-
-fastq@^1.6.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858"
- integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
- dependencies:
- reusify "^1.0.4"
-
-figures@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
- integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
- dependencies:
- escape-string-regexp "^1.0.5"
-
-fill-range@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
- integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
- dependencies:
- to-regex-range "^5.0.1"
-
-follow-redirects@^1.10.0:
- version "1.14.0"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.0.tgz#f5d260f95c5f8c105894491feee5dc8993b402fe"
- integrity sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==
-
-fs-constants@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
- integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
-
-fs-minipass@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
- integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
- dependencies:
- minipass "^3.0.0"
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-get-intrinsic@^1.0.2:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
- integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
- dependencies:
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
-
-get-stream@^4.0.0, get-stream@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
- integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
- dependencies:
- pump "^3.0.0"
-
-get-stream@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
- integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
- dependencies:
- pump "^3.0.0"
-
-glob-parent@^5.1.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
- integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
- dependencies:
- is-glob "^4.0.1"
-
-glob@^7.1.3, glob@^7.1.6:
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-global-agent@^2.1.12:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.2.0.tgz#566331b0646e6bf79429a16877685c4a1fbf76dc"
- integrity sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==
- dependencies:
- boolean "^3.0.1"
- core-js "^3.6.5"
- es6-error "^4.1.1"
- matcher "^3.0.0"
- roarr "^2.15.3"
- semver "^7.3.2"
- serialize-error "^7.0.1"
-
-global-dirs@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d"
- integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==
- dependencies:
- ini "1.3.7"
-
-globalthis@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b"
- integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==
- dependencies:
- define-properties "^1.1.3"
-
-globby@^11.0.1:
- version "11.0.3"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
- integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.1.1"
- ignore "^5.1.4"
- merge2 "^1.3.0"
- slash "^3.0.0"
-
-got@11.4.0:
- version "11.4.0"
- resolved "https://registry.yarnpkg.com/got/-/got-11.4.0.tgz#1f0910310572af4efcc6890e1dacd7affb710b39"
- integrity sha512-XysJZuZNVpaQ37Oo2LV90MIkPeYITehyy1A0QzO1JwOXm8EWuEf9eeGk2XuHePvLEGnm9AVOI37bHwD6KYyBtg==
- dependencies:
- "@sindresorhus/is" "^2.1.1"
- "@szmarczak/http-timer" "^4.0.5"
- "@types/cacheable-request" "^6.0.1"
- "@types/responselike" "^1.0.0"
- cacheable-lookup "^5.0.3"
- cacheable-request "^7.0.1"
- decompress-response "^6.0.0"
- http2-wrapper "^1.0.0-beta.4.5"
- lowercase-keys "^2.0.0"
- p-cancelable "^2.0.0"
- responselike "^2.0.0"
-
-got@^11.7.0:
- version "11.8.2"
- resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
- integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==
- dependencies:
- "@sindresorhus/is" "^4.0.0"
- "@szmarczak/http-timer" "^4.0.5"
- "@types/cacheable-request" "^6.0.1"
- "@types/responselike" "^1.0.0"
- cacheable-lookup "^5.0.3"
- cacheable-request "^7.0.1"
- decompress-response "^6.0.0"
- http2-wrapper "^1.0.0-beta.5.2"
- lowercase-keys "^2.0.0"
- p-cancelable "^2.0.0"
- responselike "^2.0.0"
-
-got@^9.6.0:
- version "9.6.0"
- resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
- integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
- dependencies:
- "@sindresorhus/is" "^0.14.0"
- "@szmarczak/http-timer" "^1.1.2"
- cacheable-request "^6.0.0"
- decompress-response "^3.3.0"
- duplexer3 "^0.1.4"
- get-stream "^4.1.0"
- lowercase-keys "^1.0.1"
- mimic-response "^1.0.1"
- p-cancelable "^1.0.0"
- to-readable-stream "^1.0.0"
- url-parse-lax "^3.0.0"
-
-graceful-fs@^4.1.2:
- version "4.1.15"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
- integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
-
-grapheme-splitter@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
- integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
-
-gunzip-maybe@^1.4.2:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac"
- integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==
- dependencies:
- browserify-zlib "^0.1.4"
- is-deflate "^1.0.0"
- is-gzip "^1.0.0"
- peek-stream "^1.1.0"
- pumpify "^1.3.3"
- through2 "^2.0.3"
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
-
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-symbols@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
- integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
-
-has-yarn@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
- integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
-
-has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
-
-hosted-git-info@^3.0.4, hosted-git-info@^3.0.7:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.8.tgz#6e35d4cc87af2c5f816e4cb9ce350ba87a3f370d"
- integrity sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==
- dependencies:
- lru-cache "^6.0.0"
-
html2canvas@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.1.4.tgz#53ae91cd26e9e9e623c56533cccb2e3f57c8124c"
@@ -1491,2086 +21,7 @@ html2canvas@^1.1.4:
dependencies:
css-line-break "1.1.1"
-http-cache-semantics@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
- integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
-
-http2-wrapper@^1.0.0-beta.4.5, http2-wrapper@^1.0.0-beta.5.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
- integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
- dependencies:
- quick-lru "^5.1.1"
- resolve-alpn "^1.0.0"
-
-iconv-lite@^0.4.24, iconv-lite@^0.4.4:
- version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
- integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
- dependencies:
- safer-buffer ">= 2.1.2 < 3"
-
-ieee754@^1.1.13:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
- integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-
-ignore@^5.1.4, ignore@^5.1.8:
- version "5.1.8"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
- integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
-
-immediate@~3.0.5:
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
- integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
-
-import-lazy@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
- integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
-
-imurmurhash@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2, inherits@~2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
- integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-ini@1.3.7, ini@~1.3.0:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
- integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
-
-is-callable@^1.1.5:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
- integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
-
-is-ci@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
- integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
- dependencies:
- ci-info "^2.0.0"
-
-is-deflate@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14"
- integrity sha1-yGKQHDwWH7CdrHzcfnhPgOmPLxQ=
-
-is-docker@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
- integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
-
-is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
-
-is-fullwidth-code-point@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
- integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-glob@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
- integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-gzip@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83"
- integrity sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=
-
-is-installed-globally@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
- integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
- dependencies:
- global-dirs "^2.0.1"
- is-path-inside "^3.0.1"
-
-is-interactive@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
- integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
-
-is-npm@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
- integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
-
-is-number@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
- integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-obj@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
- integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
-
-is-path-inside@^3.0.1:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
- integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
-
-is-stream@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
- integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
-
-is-typedarray@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
- integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-
-is-unicode-supported@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
- integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
-
-is-wsl@^2.1.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
- integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
- dependencies:
- is-docker "^2.0.0"
-
-is-yarn-global@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
- integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
-
-is@^3.2.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/is/-/is-3.3.0.tgz#61cff6dd3c4193db94a3d62582072b44e5645d79"
- integrity sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==
-
-isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-js-yaml@^3.10.0:
- version "3.14.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
- integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
-
-js-yaml@^3.13.1:
- version "3.13.1"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
- integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
-
-json-buffer@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
- integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
-
-json-buffer@3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
- integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
-
-json-file-plus@^3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/json-file-plus/-/json-file-plus-3.3.1.tgz#f4363806b82819ff8803d83d539d6a9edd2a5258"
- integrity sha512-wo0q1UuiV5NsDPQDup1Km8IwEeqe+olr8tkWxeJq9Bjtcp7DZ0l+yrg28fSC3DEtrE311mhTZ54QGS6oiqnZEA==
- dependencies:
- is "^3.2.1"
- node.extend "^2.0.0"
- object.assign "^4.1.0"
- promiseback "^2.0.2"
- safer-buffer "^2.0.2"
-
-json-stringify-safe@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
- integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-
-jszip@3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.4.0.tgz#1a69421fa5f0bb9bc222a46bca88182fba075350"
- integrity sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==
- dependencies:
- lie "~3.3.0"
- pako "~1.0.2"
- readable-stream "~2.3.6"
- set-immediate-shim "~1.0.1"
-
-jszip@^3.2.2:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.6.0.tgz#839b72812e3f97819cc13ac4134ffced95dd6af9"
- integrity sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==
- dependencies:
- lie "~3.3.0"
- pako "~1.0.2"
- readable-stream "~2.3.6"
- set-immediate-shim "~1.0.1"
-
-keyv@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
- integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
- dependencies:
- json-buffer "3.0.0"
-
-keyv@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
- integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
- dependencies:
- json-buffer "3.0.1"
-
-latest-version@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
- integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
- dependencies:
- package-json "^6.3.0"
-
-lie@~3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
- integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
- dependencies:
- immediate "~3.0.5"
-
-lodash.assign@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
- integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
-
-lodash.assignin@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
- integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI=
-
-lodash.camelcase@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
-
-lodash.chunk@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc"
- integrity sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=
-
-lodash.clone@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6"
- integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=
-
-lodash.clonedeep@^4.3.0, lodash.clonedeep@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
- integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
-
-lodash.constant@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash.constant/-/lodash.constant-3.0.0.tgz#bfe05cce7e515b3128925d6362138420bd624910"
- integrity sha1-v+Bczn5RWzEokl1jYhOEIL1iSRA=
-
-lodash.defaults@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
- integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
-
-lodash.endswith@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09"
- integrity sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=
-
-lodash.filter@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
- integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=
-
-lodash.find@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
- integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
-
-lodash.findindex@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.findindex/-/lodash.findindex-4.6.0.tgz#a3245dee61fb9b6e0624b535125624bb69c11106"
- integrity sha1-oyRd7mH7m24GJLU1ElYku2nBEQY=
-
-lodash.findkey@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.findkey/-/lodash.findkey-4.6.0.tgz#83058e903b51cbb759d09ccf546dea3ea39c4718"
- integrity sha1-gwWOkDtRy7dZ0JzPVG3qPqOcRxg=
-
-lodash.flatmap@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz#ef8cbf408f6e48268663345305c6acc0b778702e"
- integrity sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=
-
-lodash.flatten@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
- integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
-
-lodash.flattendeep@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
- integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
-
-lodash.foreach@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
- integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=
-
-lodash.get@^4.4.2:
- version "4.4.2"
- resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
- integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
-
-lodash.groupby@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1"
- integrity sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=
-
-lodash.has@^4.5.2:
- version "4.5.2"
- resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862"
- integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=
-
-lodash.invert@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.invert/-/lodash.invert-4.3.0.tgz#8ffe20d4b616f56bea8f1aa0c6ebd80dcf742aee"
- integrity sha1-j/4g1LYW9WvqjxqgxuvYDc90Ku4=
-
-lodash.isboolean@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
- integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
-
-lodash.isempty@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
- integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=
-
-lodash.isequal@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
- integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
-
-lodash.isfunction@^3.0.9:
- version "3.0.9"
- resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
- integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
-
-lodash.isnumber@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
- integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
-
-lodash.isobject@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d"
- integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
-
-lodash.isstring@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
- integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
-
-lodash.isundefined@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48"
- integrity sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=
-
-lodash.keys@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205"
- integrity sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=
-
-lodash.last@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash.last/-/lodash.last-3.0.0.tgz#242f663112dd4c6e63728c60a3c909d1bdadbd4c"
- integrity sha1-JC9mMRLdTG5jcoxgo8kJ0b2tvUw=
-
-lodash.map@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
- integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
-
-lodash.merge@^4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-
-lodash.omit@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
- integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=
-
-lodash.orderby@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.orderby/-/lodash.orderby-4.6.0.tgz#e697f04ce5d78522f54d9338b32b81a3393e4eb3"
- integrity sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=
-
-lodash.reduce@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
- integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=
-
-lodash.set@^4.3.2:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
- integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
-
-lodash.size@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.size/-/lodash.size-4.2.0.tgz#71fe75ed3eabdb2bcb73a1b0b4f51c392ee27b86"
- integrity sha1-cf517T6r2yvLc6GwtPUcOS7ie4Y=
-
-lodash.sortby@^4.7.0:
- version "4.7.0"
- resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
- integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
-
-lodash.sum@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/lodash.sum/-/lodash.sum-4.0.2.tgz#ad90e397965d803d4f1ff7aa5b2d0197f3b4637b"
- integrity sha1-rZDjl5ZdgD1PH/eqWy0Bl/O0Y3s=
-
-lodash.topairs@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.topairs/-/lodash.topairs-4.3.0.tgz#3b6deaa37d60fb116713c46c5f17ea190ec48d64"
- integrity sha1-O23qo31g+xFnE8RsXxfqGQ7EjWQ=
-
-lodash.transform@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0"
- integrity sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=
-
-lodash.union@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
- integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
-
-lodash.uniq@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
- integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-
-lodash.upperfirst@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce"
- integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=
-
-lodash.values@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
- integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
-
-lodash@^4.17.15:
- version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
- integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-log-symbols@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
- integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
- dependencies:
- chalk "^4.1.0"
- is-unicode-supported "^0.1.0"
-
-lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
- integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
-
-lowercase-keys@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
- integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
-
-lru-cache@^4.0.0:
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
- integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
- dependencies:
- pseudomap "^1.0.2"
- yallist "^2.1.2"
-
-lru-cache@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
- integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
- dependencies:
- yallist "^3.0.2"
-
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-macos-release@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
- integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
-
-make-dir@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
- integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
- dependencies:
- semver "^6.0.0"
-
-matcher@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
- integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==
- dependencies:
- escape-string-regexp "^4.0.0"
-
-merge2@^1.3.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
- integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-
-micromatch@4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
- integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
- dependencies:
- braces "^3.0.1"
- picomatch "^2.0.5"
-
-micromatch@^4.0.2:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
- integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
- dependencies:
- braces "^3.0.1"
- picomatch "^2.2.3"
-
-mimic-fn@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
- integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-
-mimic-response@^1.0.0, mimic-response@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
- integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
-
-mimic-response@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
- integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-
-minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
-minipass@^3.0.0:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd"
- integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==
- dependencies:
- yallist "^4.0.0"
-
-minizlib@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
- integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
- dependencies:
- minipass "^3.0.0"
- yallist "^4.0.0"
-
-mkdirp@^0.5.1:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
-
-mkdirp@^1.0.3, mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-ms@2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-ms@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
-mute-stream@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
- integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-
-needle@2.6.0, needle@^2.3.3, needle@^2.5.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe"
- integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==
- dependencies:
- debug "^3.2.6"
- iconv-lite "^0.4.4"
- sax "^1.2.4"
-
-nice-try@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
- integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-
-node.extend@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-2.0.2.tgz#b4404525494acc99740f3703c496b7d5182cc6cc"
- integrity sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==
- dependencies:
- has "^1.0.3"
- is "^3.2.1"
-
-normalize-url@^4.1.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
- integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
-
-npm-run-path@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
- integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
- dependencies:
- path-key "^2.0.0"
-
-object-hash@^2.0.3:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.1.1.tgz#9447d0279b4fcf80cff3259bf66a1dc73afabe09"
- integrity sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==
-
-object-keys@^1.0.12, object-keys@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
- integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-
-object.assign@^4.1.0:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
- integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
- dependencies:
- call-bind "^1.0.0"
- define-properties "^1.1.3"
- has-symbols "^1.0.1"
- object-keys "^1.1.1"
-
-once@^1.3.0, once@^1.3.1, once@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
- dependencies:
- wrappy "1"
-
-once@~1.3.0:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
- integrity sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=
- dependencies:
- wrappy "1"
-
-onetime@^5.1.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
- integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
- dependencies:
- mimic-fn "^2.1.0"
-
onscan.js@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/onscan.js/-/onscan.js-1.5.2.tgz#14ed636e5f4c3f0a78bacbf9a505dad3140ee341"
integrity sha512-9oGYy2gXYRjvXO9GYqqVca0VuCTAmWhbmX3egBSBP13rXiMNb+dKPJzKFEeECGqPBpf0m40Zoo+GUQ7eCackdw==
-
-open@^7.0.3:
- version "7.4.2"
- resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
- integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
- dependencies:
- is-docker "^2.0.0"
- is-wsl "^2.1.1"
-
-ora@5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f"
- integrity sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==
- dependencies:
- bl "^4.0.3"
- chalk "^4.1.0"
- cli-cursor "^3.1.0"
- cli-spinners "^2.5.0"
- is-interactive "^1.0.0"
- log-symbols "^4.0.0"
- strip-ansi "^6.0.0"
- wcwidth "^1.0.1"
-
-os-name@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
- integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
- dependencies:
- macos-release "^2.2.0"
- windows-release "^3.1.0"
-
-os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
- integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-p-cancelable@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
- integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-
-p-cancelable@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.0.tgz#4d51c3b91f483d02a0d300765321fca393d758dd"
- integrity sha512-HAZyB3ZodPo+BDpb4/Iu7Jv4P6cSazBz9ZM0ChhEXp70scx834aWCEjQRwgt41UzzejUAPdbqqONfRWTPYrPAQ==
-
-p-finally@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
- integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
-
-p-limit@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
- integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
- dependencies:
- p-try "^2.0.0"
-
-p-map@2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
- integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
-
-p-map@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
- integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
- dependencies:
- aggregate-error "^3.0.0"
-
-p-try@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
- integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-
-package-json@^6.3.0:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
- integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
- dependencies:
- got "^9.6.0"
- registry-auth-token "^4.0.0"
- registry-url "^5.0.0"
- semver "^6.2.0"
-
-pako@~0.2.0:
- version "0.2.9"
- resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
- integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
-
-pako@~1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
- integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
-
-parse-link-header@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parse-link-header/-/parse-link-header-1.0.1.tgz#bedfe0d2118aeb84be75e7b025419ec8a61140a7"
- integrity sha1-vt/g0hGK64S+deewJUGeyKYRQKc=
- dependencies:
- xtend "~4.0.1"
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-
-path-key@^2.0.0, path-key@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
- integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
-
-path-key@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
- integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-type@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
- integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
-peek-stream@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67"
- integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==
- dependencies:
- buffer-from "^1.0.0"
- duplexify "^3.5.0"
- through2 "^2.0.3"
-
-picomatch@^2.0.5, picomatch@^2.2.1, picomatch@^2.2.3:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
- integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
-
-pluralize@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
- integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==
-
-prepend-http@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
- integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-
-pretty-bytes@^5.1.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
- integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
-
-process-nextick-args@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
- integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
-
-progress@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
- integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
-
-promise-deferred@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/promise-deferred/-/promise-deferred-2.0.3.tgz#b99c9588820798501862a593d49cece51d06fd7f"
- integrity sha512-n10XaoznCzLfyPFOlEE8iurezHpxrYzyjgq/1eW9Wk1gJwur/N7BdBmjJYJpqMeMcXK4wEbzo2EvZQcqjYcKUQ==
- dependencies:
- promise "^7.3.1"
-
-promise-fs@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/promise-fs/-/promise-fs-2.1.1.tgz#0b725a592c165ff16157d1f13640ba390637e557"
- integrity sha512-43p7e4QzAQ3w6eyN0+gbBL7jXiZFWLWYITg9wIObqkBySu/a5K1EDcQ/S6UyB/bmiZWDA4NjTbcopKLTaKcGSw==
- dependencies:
- "@octetstream/promisify" "2.0.2"
-
-promise-queue@^2.2.5:
- version "2.2.5"
- resolved "https://registry.yarnpkg.com/promise-queue/-/promise-queue-2.2.5.tgz#2f6f5f7c0f6d08109e967659c79b88a9ed5e93b4"
- integrity sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=
-
-"promise@>=3.2 <8", promise@^7.3.1:
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
- integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
- dependencies:
- asap "~2.0.3"
-
-promiseback@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/promiseback/-/promiseback-2.0.3.tgz#bd468d86930e8cd44bfc3292de9a6fbafb6378e6"
- integrity sha512-VZXdCwS0ppVNTIRfNsCvVwJAaP2b+pxQF7lM8DMWfmpNWyTxB6O5YNbzs+8z0ki/KIBHKHk308NTIl4kJUem3w==
- dependencies:
- is-callable "^1.1.5"
- promise-deferred "^2.0.3"
-
-proxy-from-env@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
- integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
-
-pseudomap@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
- integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-
-pump@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
- integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pump@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
- integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pumpify@^1.3.3:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
- integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
- dependencies:
- duplexify "^3.6.0"
- inherits "^2.0.3"
- pump "^2.0.0"
-
-pupa@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
- integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
- dependencies:
- escape-goat "^2.0.0"
-
-queue-microtask@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
- integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-
-queue@^6.0.1:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65"
- integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==
- dependencies:
- inherits "~2.0.3"
-
-quick-lru@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
- integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
-
-rc@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
- integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
- dependencies:
- deep-extend "^0.6.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
-
-readable-stream@^2.0.0, readable-stream@~2.3.6:
- version "2.3.7"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
- integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
- integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
- dependencies:
- inherits "^2.0.3"
- string_decoder "^1.1.1"
- util-deprecate "^1.0.1"
-
-registry-auth-token@^4.0.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250"
- integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==
- dependencies:
- rc "^1.2.8"
-
-registry-url@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
- integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
- dependencies:
- rc "^1.2.8"
-
-resolve-alpn@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.1.2.tgz#30b60cfbb0c0b8dc897940fe13fe255afcdd4d28"
- integrity sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==
-
-responselike@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
- integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
- dependencies:
- lowercase-keys "^1.0.0"
-
-responselike@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
- integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
- dependencies:
- lowercase-keys "^2.0.0"
-
-restore-cursor@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
- integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
- dependencies:
- onetime "^5.1.0"
- signal-exit "^3.0.2"
-
-reusify@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
- integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-
-rimraf@^2.6.3:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
-rimraf@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
-roarr@^2.15.3:
- version "2.15.4"
- resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd"
- integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==
- dependencies:
- boolean "^3.0.1"
- detect-node "^2.0.4"
- globalthis "^1.0.1"
- json-stringify-safe "^5.0.1"
- semver-compare "^1.0.0"
- sprintf-js "^1.1.2"
-
-run-async@^2.4.0:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
- integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
-
-run-parallel@^1.1.9:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
- integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
- dependencies:
- queue-microtask "^1.2.2"
-
-rxjs@^6.6.0:
- version "6.6.7"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
- integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
- dependencies:
- tslib "^1.9.0"
-
-safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@~5.2.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
- integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@~2.1.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
- integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-
-sax@>=0.6.0, sax@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
-semver-compare@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
- integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
-
-semver-diff@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
- integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
- dependencies:
- semver "^6.3.0"
-
-semver@^5.5.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
- integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
-
-semver@^5.5.1:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
- integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-semver@^7.0.0, semver@^7.1.2, semver@^7.3.2, semver@^7.3.4:
- version "7.3.5"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
- integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
- dependencies:
- lru-cache "^6.0.0"
-
-serialize-error@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
- integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==
- dependencies:
- type-fest "^0.13.1"
-
-set-immediate-shim@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
- integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
-
-shebang-command@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
- integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
- dependencies:
- shebang-regex "^1.0.0"
-
-shebang-command@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
- integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
- dependencies:
- shebang-regex "^3.0.0"
-
-shebang-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
- integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
-
-shebang-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
- integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
- integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
-
-slash@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
- integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-
-snyk-config@4.0.0, snyk-config@^4.0.0-rc.2:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/snyk-config/-/snyk-config-4.0.0.tgz#21d459f19087991246cc07a7ffb4501dce6f4159"
- integrity sha512-E6jNe0oUjjzVASWBOAc/mA23DhbzABDF9MI6UZvl0gylh2NSXSXw2/LjlqMNOKL2c1qkbSkzLOdIX5XACoLCAQ==
- dependencies:
- async "^3.2.0"
- debug "^4.1.1"
- lodash.merge "^4.6.2"
- minimist "^1.2.5"
-
-snyk-cpp-plugin@2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/snyk-cpp-plugin/-/snyk-cpp-plugin-2.2.1.tgz#55891511a43a6448e5a7c836a94f66f70fa705eb"
- integrity sha512-NFwVLMCqKTocY66gcim0ukF6e31VRDJqDapg5sy3vCHqlD1OCNUXSK/aI4VQEEndDrsnFmQepsL5KpEU0dDRIQ==
- dependencies:
- "@snyk/dep-graph" "^1.19.3"
- chalk "^4.1.0"
- debug "^4.1.1"
- hosted-git-info "^3.0.7"
- tslib "^2.0.0"
-
-snyk-docker-plugin@4.19.3:
- version "4.19.3"
- resolved "https://registry.yarnpkg.com/snyk-docker-plugin/-/snyk-docker-plugin-4.19.3.tgz#14569f25c52a3fc71a20f80f5beac4ccdc326c11"
- integrity sha512-5WkXyT7uY5NrTOvEqxeMqb6dDcskT3c/gbHUTOyPuvE6tMut+OOYK8RRXbwZFeLzpS8asq4e1R7U7syYG3VXwg==
- dependencies:
- "@snyk/dep-graph" "^1.21.0"
- "@snyk/rpm-parser" "^2.0.0"
- "@snyk/snyk-docker-pull" "3.2.3"
- chalk "^2.4.2"
- debug "^4.1.1"
- docker-modem "2.1.3"
- dockerfile-ast "0.2.0"
- elfy "^1.0.0"
- event-loop-spinner "^2.0.0"
- gunzip-maybe "^1.4.2"
- mkdirp "^1.0.4"
- semver "^7.3.4"
- snyk-nodejs-lockfile-parser "1.30.2"
- tar-stream "^2.1.0"
- tmp "^0.2.1"
- tslib "^1"
- uuid "^8.2.0"
-
-snyk-go-parser@1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/snyk-go-parser/-/snyk-go-parser-1.4.1.tgz#df16a5fbd7a517ee757268ef081abc33506c8857"
- integrity sha512-StU3uHB85VMEkcgXta63M0Fgd+9cs5sMCjQXTBoYTdE4dxarPn7U67yCuwkRRdZdny1ZXtzfY8LKns9i0+dy9w==
- dependencies:
- toml "^3.0.0"
- tslib "^1.10.0"
-
-snyk-go-plugin@1.17.0:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/snyk-go-plugin/-/snyk-go-plugin-1.17.0.tgz#56d0c92d7def29ba4c3c2030c5830093e3b0dd26"
- integrity sha512-1jAYPRgMapO2BYL+HWsUq5gsAiDGmI0Pn7omc0lk24tcUOMhUB+1hb0u9WBMNzHvXBjevBkjOctjpnt2hMKN6Q==
- dependencies:
- "@snyk/dep-graph" "^1.23.1"
- "@snyk/graphlib" "2.1.9-patch.3"
- debug "^4.1.1"
- snyk-go-parser "1.4.1"
- tmp "0.2.1"
- tslib "^1.10.0"
-
-snyk-gradle-plugin@3.14.2:
- version "3.14.2"
- resolved "https://registry.yarnpkg.com/snyk-gradle-plugin/-/snyk-gradle-plugin-3.14.2.tgz#898b051f679e681b6d859f0ca84a500ac028af7d"
- integrity sha512-l/nivKDZz7e2wymrwP6g2WQD8qgaYeE22SnbZrfIpwGolif81U28A9FsRedwkxKyB/shrM0vGEoD3c3zI8NLBw==
- dependencies:
- "@snyk/cli-interface" "2.11.0"
- "@snyk/dep-graph" "^1.28.0"
- "@snyk/java-call-graph-builder" "1.20.0"
- "@types/debug" "^4.1.4"
- chalk "^3.0.0"
- debug "^4.1.1"
- tmp "0.2.1"
- tslib "^2.0.0"
-
-snyk-module@3.1.0, snyk-module@^3.0.0, snyk-module@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/snyk-module/-/snyk-module-3.1.0.tgz#3e088ff473ddf0d4e253a46ea6749d76d8e6e7ba"
- integrity sha512-HHuOYEAACpUpkFgU8HT57mmxmonaJ4O3YADoSkVhnhkmJ+AowqZyJOau703dYHNrq2DvQ7qYw81H7yyxS1Nfjw==
- dependencies:
- debug "^4.1.1"
- hosted-git-info "^3.0.4"
-
-snyk-mvn-plugin@2.25.3:
- version "2.25.3"
- resolved "https://registry.yarnpkg.com/snyk-mvn-plugin/-/snyk-mvn-plugin-2.25.3.tgz#fb7f6fa1d565b9f07c032e8b34e6308c310b2a27"
- integrity sha512-JAxOThX51JDbgMMjp3gQDVi07G9VgTYSF06QC7f5LNA0zoXNr743e2rm78RGw5bqE3JRjZxEghiLHPPuvS5DDg==
- dependencies:
- "@snyk/cli-interface" "2.11.0"
- "@snyk/dep-graph" "^1.23.1"
- "@snyk/java-call-graph-builder" "1.19.1"
- debug "^4.1.1"
- glob "^7.1.6"
- needle "^2.5.0"
- tmp "^0.1.0"
- tslib "1.11.1"
-
-snyk-nodejs-lockfile-parser@1.30.2:
- version "1.30.2"
- resolved "https://registry.yarnpkg.com/snyk-nodejs-lockfile-parser/-/snyk-nodejs-lockfile-parser-1.30.2.tgz#8dbb64c42382aeaf4488c36e48c1e48eb75a1584"
- integrity sha512-wI3VXVYO/ok0uaQm5i+Koo4rKBNilYC/QRIQFlyGbZXf+WBdRcTBKVDfTy8uNfUhMRSGzd84lNclMnetU9Y+vw==
- dependencies:
- "@snyk/graphlib" "2.1.9-patch.3"
- "@yarnpkg/lockfile" "^1.1.0"
- event-loop-spinner "^2.0.0"
- got "11.4.0"
- lodash.clonedeep "^4.5.0"
- lodash.flatmap "^4.5.0"
- lodash.isempty "^4.4.0"
- lodash.set "^4.3.2"
- lodash.topairs "^4.3.0"
- p-map "2.1.0"
- snyk-config "^4.0.0-rc.2"
- tslib "^1.9.3"
- uuid "^8.3.0"
- yaml "^1.9.2"
-
-snyk-nodejs-lockfile-parser@1.32.0:
- version "1.32.0"
- resolved "https://registry.yarnpkg.com/snyk-nodejs-lockfile-parser/-/snyk-nodejs-lockfile-parser-1.32.0.tgz#2e25ea8622ef03ae7457a93ae70e156d6c46c2ef"
- integrity sha512-FdYa/7NibnJPqBfobyw5jgI1/rd0LpMZf2W4WYYLRc2Hz7LZjKAByPjIX6qoA+lB9SC7yk5HYwWj2n4Fbg/DDw==
- dependencies:
- "@snyk/graphlib" "2.1.9-patch.3"
- "@yarnpkg/core" "^2.4.0"
- "@yarnpkg/lockfile" "^1.1.0"
- event-loop-spinner "^2.0.0"
- got "11.4.0"
- lodash.clonedeep "^4.5.0"
- lodash.flatmap "^4.5.0"
- lodash.isempty "^4.4.0"
- lodash.set "^4.3.2"
- lodash.topairs "^4.3.0"
- p-map "2.1.0"
- snyk-config "^4.0.0-rc.2"
- tslib "^1.9.3"
- uuid "^8.3.0"
- yaml "^1.9.2"
-
-snyk-nuget-plugin@1.21.1:
- version "1.21.1"
- resolved "https://registry.yarnpkg.com/snyk-nuget-plugin/-/snyk-nuget-plugin-1.21.1.tgz#a79bbc65456823a1148119873226afb0e4907ec8"
- integrity sha512-nRtedIvrow5ODqOKkQWolKrxn8ZoNL3iNJGuW0jNhwv+/9K0XE1UORM5F1ENAsd+nzCSO/kiYAXCc5CNK8HWEw==
- dependencies:
- debug "^4.1.1"
- dotnet-deps-parser "5.0.0"
- jszip "3.4.0"
- snyk-paket-parser "1.6.0"
- tslib "^1.11.2"
- xml2js "^0.4.17"
-
-snyk-paket-parser@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/snyk-paket-parser/-/snyk-paket-parser-1.6.0.tgz#f70c423b33d31484c8c4cae74bb7f5deb9bbc382"
- integrity sha512-6htFynjBe/nakclEHUZ1A3j5Eu32/0pNve5Qm4MFn3YQmJgj7UcAO8hdyK3QfzEY29/kAv/rkJQg+SKshn+N9Q==
- dependencies:
- tslib "^1.9.3"
-
-snyk-php-plugin@1.9.2:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/snyk-php-plugin/-/snyk-php-plugin-1.9.2.tgz#282ef733060aab49da23e1fb2d2dd1af8f71f7cd"
- integrity sha512-IQcdsQBqqXVRY5DatlI7ASy4flbhtU2V7cr4P2rK9rkFnVHO6LHcitwKXVZa9ocdOmpZDzk7U6iwHJkVFcR6OA==
- dependencies:
- "@snyk/cli-interface" "^2.9.1"
- "@snyk/composer-lockfile-parser" "^1.4.1"
- tslib "1.11.1"
-
-snyk-poetry-lockfile-parser@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/snyk-poetry-lockfile-parser/-/snyk-poetry-lockfile-parser-1.1.6.tgz#bab5a279c103cbcca8eb86ab87717b115592881e"
- integrity sha512-MoekbWOZPj9umfukjk2bd2o3eRj0OyO+58sxq9crMtHmTlze4h0/Uj4+fb0JFPBOtBO3c2zwbA+dvFQmpKoOTA==
- dependencies:
- "@snyk/cli-interface" "^2.9.2"
- "@snyk/dep-graph" "^1.23.0"
- debug "^4.2.0"
- toml "^3.0.0"
- tslib "^2.0.0"
-
-snyk-policy@1.19.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/snyk-policy/-/snyk-policy-1.19.0.tgz#0cbc442d9503970fb3afea938f57d57993a914ad"
- integrity sha512-XYjhOTRPFA7NfDUsH6uH1fbML2OgSFsqdUPbud7x01urNP9CHXgUgAD4NhKMi3dVQK+7IdYadWt0wrFWw4y+qg==
- dependencies:
- debug "^4.1.1"
- email-validator "^2.0.4"
- js-yaml "^3.13.1"
- lodash.clonedeep "^4.5.0"
- promise-fs "^2.1.1"
- semver "^6.0.0"
- snyk-module "^3.0.0"
- snyk-resolve "^1.1.0"
- snyk-try-require "^2.0.0"
-
-snyk-python-plugin@1.19.8:
- version "1.19.8"
- resolved "https://registry.yarnpkg.com/snyk-python-plugin/-/snyk-python-plugin-1.19.8.tgz#9e4dfa8ed7e16ef2752f934b786d2e033de62ce0"
- integrity sha512-LMKVnv0J4X/qHMoKB17hMND0abWtm9wdgI4xVzrOcf2Vtzs3J87trRhwLxQA2lMoBW3gcjtTeBUvNKaxikSVeQ==
- dependencies:
- "@snyk/cli-interface" "^2.0.3"
- snyk-poetry-lockfile-parser "^1.1.6"
- tmp "0.0.33"
-
-snyk-resolve-deps@4.7.2:
- version "4.7.2"
- resolved "https://registry.yarnpkg.com/snyk-resolve-deps/-/snyk-resolve-deps-4.7.2.tgz#11e7051110dadd8756819594bb30e6b88777a8b4"
- integrity sha512-Bmtr7QdRL2b3Js+mPDmvXbkprOpzO8aUFXqR0nJKAOlUVQqZ84yiuT0n/mssEiJJ0vP+k0kZvTeiTwgio4KZRg==
- dependencies:
- ansicolors "^0.3.2"
- debug "^4.1.1"
- lodash.assign "^4.2.0"
- lodash.assignin "^4.2.0"
- lodash.clone "^4.5.0"
- lodash.flatten "^4.4.0"
- lodash.get "^4.4.2"
- lodash.set "^4.3.2"
- lru-cache "^4.0.0"
- semver "^5.5.1"
- snyk-module "^3.1.0"
- snyk-resolve "^1.0.0"
- snyk-tree "^1.0.0"
- snyk-try-require "^1.1.1"
- then-fs "^2.0.0"
-
-snyk-resolve@1.1.0, snyk-resolve@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/snyk-resolve/-/snyk-resolve-1.1.0.tgz#52740cb01ba477851086855f9857b3a44296ee0e"
- integrity sha512-OZMF8I8TOu0S58Z/OS9mr8jkEzGAPByCsAkrWlcmZgPaE0RsxVKVIFPhbMNy/JlYswgGDYYIEsNw+e0j1FnTrw==
- dependencies:
- debug "^4.1.1"
- promise-fs "^2.1.1"
-
-snyk-resolve@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/snyk-resolve/-/snyk-resolve-1.0.1.tgz#eaa4a275cf7e2b579f18da5b188fe601b8eed9ab"
- integrity sha512-7+i+LLhtBo1Pkth01xv+RYJU8a67zmJ8WFFPvSxyCjdlKIcsps4hPQFebhz+0gC5rMemlaeIV6cqwqUf9PEDpw==
- dependencies:
- debug "^3.1.0"
- then-fs "^2.0.0"
-
-snyk-sbt-plugin@2.11.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/snyk-sbt-plugin/-/snyk-sbt-plugin-2.11.0.tgz#f5469dcf5589e34575fc901e2064475582cc3e48"
- integrity sha512-wUqHLAa3MzV6sVO+05MnV+lwc+T6o87FZZaY+43tQPytBI2Wq23O3j4POREM4fa2iFfiQJoEYD6c7xmhiEUsSA==
- dependencies:
- debug "^4.1.1"
- semver "^6.1.2"
- tmp "^0.1.0"
- tree-kill "^1.2.2"
- tslib "^1.10.0"
-
-snyk-tree@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/snyk-tree/-/snyk-tree-1.0.0.tgz#0fb73176dbf32e782f19100294160448f9111cc8"
- integrity sha1-D7cxdtvzLngvGRAClBYESPkRHMg=
- dependencies:
- archy "^1.0.0"
-
-snyk-try-require@1.3.1, snyk-try-require@^1.1.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/snyk-try-require/-/snyk-try-require-1.3.1.tgz#6e026f92e64af7fcccea1ee53d524841e418a212"
- integrity sha1-bgJvkuZK9/zM6h7lPVJIQeQYohI=
- dependencies:
- debug "^3.1.0"
- lodash.clonedeep "^4.3.0"
- lru-cache "^4.0.0"
- then-fs "^2.0.0"
-
-snyk-try-require@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/snyk-try-require/-/snyk-try-require-2.0.1.tgz#076ae9bc505d64d28389452ce19fcac28f26655a"
- integrity sha512-VCOfFIvqLMXgCXEdooQgu3A40XYIFBnj0X8Y01RJ5iAbu08b4WKGN/uAKaRVF30dABS4EcjsalmCO+YlKUPEIA==
- dependencies:
- debug "^4.1.1"
- lodash.clonedeep "^4.3.0"
- lru-cache "^5.1.1"
-
-snyk@^1.518.0:
- version "1.564.0"
- resolved "https://registry.yarnpkg.com/snyk/-/snyk-1.564.0.tgz#c8c511128351f8b8fe239b010b6799f40bb659c5"
- integrity sha512-Fh4YusvJ9XdQfyz8JH9J8mBbipfgGLiF60MW9DYhQgP6h8z5uckAfd+S/uFMwPOVOIoe00fFo7aCLxFUuPcVJQ==
- dependencies:
- "@open-policy-agent/opa-wasm" "^1.2.0"
- "@snyk/cli-interface" "2.11.0"
- "@snyk/cloud-config-parser" "^1.9.2"
- "@snyk/code-client" "3.4.1"
- "@snyk/dep-graph" "^1.27.1"
- "@snyk/fix" "1.554.0"
- "@snyk/gemfile" "1.2.0"
- "@snyk/graphlib" "^2.1.9-patch.3"
- "@snyk/inquirer" "^7.3.3-patch"
- "@snyk/snyk-cocoapods-plugin" "2.5.2"
- "@snyk/snyk-hex-plugin" "1.1.4"
- abbrev "^1.1.1"
- ansi-escapes "3.2.0"
- chalk "^2.4.2"
- cli-spinner "0.2.10"
- configstore "^5.0.1"
- debug "^4.1.1"
- diff "^4.0.1"
- global-agent "^2.1.12"
- lodash.assign "^4.2.0"
- lodash.camelcase "^4.3.0"
- lodash.clonedeep "^4.5.0"
- lodash.endswith "^4.2.1"
- lodash.flatten "^4.4.0"
- lodash.flattendeep "^4.4.0"
- lodash.get "^4.4.2"
- lodash.groupby "^4.6.0"
- lodash.isempty "^4.4.0"
- lodash.isobject "^3.0.2"
- lodash.map "^4.6.0"
- lodash.omit "^4.5.0"
- lodash.orderby "^4.6.0"
- lodash.sortby "^4.7.0"
- lodash.uniq "^4.5.0"
- lodash.upperfirst "^4.3.1"
- lodash.values "^4.3.0"
- micromatch "4.0.2"
- needle "2.6.0"
- open "^7.0.3"
- ora "5.3.0"
- os-name "^3.0.0"
- promise-queue "^2.2.5"
- proxy-from-env "^1.0.0"
- rimraf "^2.6.3"
- semver "^6.0.0"
- snyk-config "4.0.0"
- snyk-cpp-plugin "2.2.1"
- snyk-docker-plugin "4.19.3"
- snyk-go-plugin "1.17.0"
- snyk-gradle-plugin "3.14.2"
- snyk-module "3.1.0"
- snyk-mvn-plugin "2.25.3"
- snyk-nodejs-lockfile-parser "1.32.0"
- snyk-nuget-plugin "1.21.1"
- snyk-php-plugin "1.9.2"
- snyk-policy "1.19.0"
- snyk-python-plugin "1.19.8"
- snyk-resolve "1.1.0"
- snyk-resolve-deps "4.7.2"
- snyk-sbt-plugin "2.11.0"
- snyk-tree "^1.0.0"
- snyk-try-require "1.3.1"
- source-map-support "^0.5.11"
- strip-ansi "^5.2.0"
- tar "^6.1.0"
- tempfile "^2.0.0"
- update-notifier "^4.1.0"
- uuid "^3.3.2"
- wrap-ansi "^5.1.0"
-
-source-map-support@^0.5.11, source-map-support@^0.5.7:
- version "0.5.16"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
- integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
- dependencies:
- buffer-from "^1.0.0"
- source-map "^0.6.0"
-
-source-map@^0.6.0:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
- integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
-split-ca@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
- integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=
-
-sprintf-js@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
- integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-
-ssh2-streams@~0.4.10:
- version "0.4.10"
- resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.10.tgz#48ef7e8a0e39d8f2921c30521d56dacb31d23a34"
- integrity sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==
- dependencies:
- asn1 "~0.2.0"
- bcrypt-pbkdf "^1.0.2"
- streamsearch "~0.1.2"
-
-ssh2@^0.8.7:
- version "0.8.9"
- resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.9.tgz#54da3a6c4ba3daf0d8477a538a481326091815f3"
- integrity sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==
- dependencies:
- ssh2-streams "~0.4.10"
-
-stream-buffers@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-3.0.2.tgz#5249005a8d5c2d00b3a32e6e0a6ea209dc4f3521"
- integrity sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==
-
-stream-shift@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
- integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
-
-stream-to-array@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353"
- integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=
- dependencies:
- any-promise "^1.1.0"
-
-stream-to-promise@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/stream-to-promise/-/stream-to-promise-2.2.0.tgz#b1edb2e1c8cb11289d1b503c08d3f2aef51e650f"
- integrity sha1-se2y4cjLESidG1A8CNPyrvUeZQ8=
- dependencies:
- any-promise "~1.3.0"
- end-of-stream "~1.1.0"
- stream-to-array "~2.3.0"
-
-streamsearch@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
- integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
-
-string-width@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
- integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
- dependencies:
- emoji-regex "^7.0.1"
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^5.1.0"
-
-string-width@^4.0.0, string-width@^4.1.0:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
- integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-string_decoder@^1.1.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
- integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
- dependencies:
- safe-buffer "~5.2.0"
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
-strip-ansi@6.0.0, strip-ansi@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
- integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
- dependencies:
- ansi-regex "^5.0.0"
-
-strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
- integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
- dependencies:
- ansi-regex "^4.1.0"
-
-strip-eof@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
- integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-
-strip-json-comments@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
-
-supports-color@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.1.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
- integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
- dependencies:
- has-flag "^4.0.0"
-
-tar-stream@^2.0.1, tar-stream@^2.1.2:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
- integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
- dependencies:
- bl "^4.0.3"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
-tar-stream@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
- integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
- dependencies:
- bl "^3.0.0"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
-tar@^6.1.0:
- version "6.1.11"
- resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
- integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==
- dependencies:
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- minipass "^3.0.0"
- minizlib "^2.1.1"
- mkdirp "^1.0.3"
- yallist "^4.0.0"
-
-temp-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
- integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=
-
-temp-dir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
- integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==
-
-tempfile@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265"
- integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU=
- dependencies:
- temp-dir "^1.0.0"
- uuid "^3.0.1"
-
-term-size@^2.1.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
- integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
-
-then-fs@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/then-fs/-/then-fs-2.0.0.tgz#72f792dd9d31705a91ae19ebfcf8b3f968c81da2"
- integrity sha1-cveS3Z0xcFqRrhnr/Piz+WjIHaI=
- dependencies:
- promise ">=3.2 <8"
-
-through2@^2.0.3:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
- integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
- dependencies:
- readable-stream "~2.3.6"
- xtend "~4.0.1"
-
-through@^2.3.6:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
- integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
-
-tmp@0.0.33, tmp@^0.0.33:
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
- integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
- dependencies:
- os-tmpdir "~1.0.2"
-
-tmp@0.2.1, tmp@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
- integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
- dependencies:
- rimraf "^3.0.0"
-
-tmp@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877"
- integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==
- dependencies:
- rimraf "^2.6.3"
-
-to-readable-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
- integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
-
-to-regex-range@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
- integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
- dependencies:
- is-number "^7.0.0"
-
-toml@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
- integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
-
-tree-kill@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
- integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
-
-treeify@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
- integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==
-
-tslib@1.11.1:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
- integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
-
-tslib@^1, tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
- integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
-
-tslib@^1.11.2, tslib@^1.13.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
- integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-
-tslib@^2.0.0, tslib@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
- integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
-
-tunnel@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
- integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
-
-tweetnacl@^0.14.3:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
- integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
-
-type-fest@^0.13.1:
- version "0.13.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
- integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
-
-type-fest@^0.21.3:
- version "0.21.3"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
- integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
-
-type-fest@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
- integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-
-typedarray-to-buffer@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
- integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
- dependencies:
- is-typedarray "^1.0.0"
-
-unique-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
- integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
- dependencies:
- crypto-random-string "^2.0.0"
-
-upath@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b"
- integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==
-
-update-notifier@^4.1.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3"
- integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==
- dependencies:
- boxen "^4.2.0"
- chalk "^3.0.0"
- configstore "^5.0.1"
- has-yarn "^2.1.0"
- import-lazy "^2.1.0"
- is-ci "^2.0.0"
- is-installed-globally "^0.3.1"
- is-npm "^4.0.0"
- is-yarn-global "^0.3.0"
- latest-version "^5.0.0"
- pupa "^2.0.1"
- semver-diff "^3.1.1"
- xdg-basedir "^4.0.0"
-
-url-parse-lax@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
- integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
- dependencies:
- prepend-http "^2.0.0"
-
-utf8@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
- integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
-
-util-deprecate@^1.0.1, util-deprecate@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
- integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-
-uuid@^3.0.1, uuid@^3.3.2:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-
-uuid@^8.2.0, uuid@^8.3.0, uuid@^8.3.2:
- version "8.3.2"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
- integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
-
-vscode-languageserver-types@^3.16.0:
- version "3.16.0"
- resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247"
- integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==
-
-wcwidth@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
- integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
- dependencies:
- defaults "^1.0.3"
-
-which@^1.2.9:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
- integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
- dependencies:
- isexe "^2.0.0"
-
-which@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
- integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
- dependencies:
- isexe "^2.0.0"
-
-widest-line@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
- integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
- dependencies:
- string-width "^4.0.0"
-
-windows-release@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
- integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==
- dependencies:
- execa "^1.0.0"
-
-wrap-ansi@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
- integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
- dependencies:
- ansi-styles "^3.2.0"
- string-width "^3.0.0"
- strip-ansi "^5.0.0"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-write-file-atomic@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
- integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
- dependencies:
- imurmurhash "^0.1.4"
- is-typedarray "^1.0.0"
- signal-exit "^3.0.2"
- typedarray-to-buffer "^3.1.5"
-
-xdg-basedir@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
- integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
-
-xml-js@^1.6.11:
- version "1.6.11"
- resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9"
- integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==
- dependencies:
- sax "^1.2.4"
-
-xml2js@0.4.23, xml2js@^0.4.17:
- version "0.4.23"
- resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
- integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
- dependencies:
- sax ">=0.6.0"
- xmlbuilder "~11.0.0"
-
-xmlbuilder@~11.0.0:
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
- integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
-
-xtend@~4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
-yallist@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
- integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-
-yallist@^3.0.2:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
- integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
-
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
-yaml-js@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/yaml-js/-/yaml-js-0.3.0.tgz#ad0893d9de881a93fd6bf936e8d89cdde309e848"
- integrity sha512-JbTUdsPiCkOyz+JOSqAVc19omTnUBnBQglhuclYov5HpWbEOz8y+ftqWjiMa9Pe/eF/dmCUeNgVs/VWg53GlgQ==
-
-yaml@^1.9.2:
- version "1.10.2"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
- integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==