diff --git a/.gitignore b/.gitignore index 39c5890fe9..9ba2c9749a 100644 --- a/.gitignore +++ b/.gitignore @@ -243,3 +243,4 @@ external_system/settings/phones_org.json /ftp_orders/hl7_rule !/ftp_orders/hl7_rule/default.json /xml_generate/templates/ +/forms/xlsx/media/ diff --git a/api/contracts/func.py b/api/contracts/func.py index 8917aa0d85..c92dc0fbb6 100644 --- a/api/contracts/func.py +++ b/api/contracts/func.py @@ -1,22 +1,22 @@ from clients.models import CardBase from contracts.models import BillingRegister -from contracts.sql_func import get_research_coast_by_prce, get_data_for_conform_billing +from contracts.sql_func import get_research_coast_by_prce, get_data_for_confirm_billing from directions.models import IstochnikiFinansirovaniya from statistic.sql_func import statistics_research_by_hospital_for_external_orders -from statistic.views import get_price_hospital -def researches_for_billing(type_price, company_id, date_start, date_end): +def researches_for_billing(type_price, company_id, date_start, date_end, price_id, is_confirmed, billing_id): sql_result = None research_coast = {} - price = None if type_price == "Заказчик": hospital_id = company_id - price = get_price_hospital(hospital_id, date_start, date_end) base = CardBase.objects.filter(internal_type=True).first() finsource = IstochnikiFinansirovaniya.objects.filter(base=base, title__in=["Договор"], hide=False).first() - sql_result = statistics_research_by_hospital_for_external_orders(date_start, date_end, hospital_id, finsource.pk) - coast_research_price = get_research_coast_by_prce((price.pk,)) + if not is_confirmed: + sql_result = statistics_research_by_hospital_for_external_orders(date_start, date_end, hospital_id, finsource.pk, price_id) + else: + sql_result = get_data_for_confirm_billing(billing_id) + coast_research_price = get_research_coast_by_prce((price_id,)) research_coast = {coast.research_id: float(coast.coast) for coast in coast_research_price} result = {} iss_data = set() @@ -39,11 +39,11 @@ def researches_for_billing(type_price, company_id, date_start, date_end): result[i.patient_card_num] = [current_data.copy()] else: result[i.patient_card_num].append(current_data.copy()) - return {"result": result, "issIds": list(iss_data), "priceId": price.pk} + return {"result": result, "issIds": list(iss_data), "priceId": price_id} def get_confirm_data_for_billing(price_id, billing_id): - sql_result = get_data_for_conform_billing(billing_id) + sql_result = get_data_for_confirm_billing(billing_id) coast_research_price = get_research_coast_by_prce((price_id,)) research_coast = {coast.research_id: float(coast.coast) for coast in coast_research_price} result = {} @@ -59,6 +59,8 @@ def get_confirm_data_for_billing(price_id, billing_id): "tube_number": i.tube_number, "coast": research_coast.get(i.research_id, 0), "execute_date": i.date_confirm, + "internal_code": i.internal_code, + "code_nmu": i.code_nmu, } if not result.get(i.patient_card_num): result[i.patient_card_num] = [current_data.copy()] diff --git a/api/contracts/urls.py b/api/contracts/urls.py index c9461af217..885f030d5c 100644 --- a/api/contracts/urls.py +++ b/api/contracts/urls.py @@ -6,6 +6,7 @@ path('create-billing', views.create_billing), path('update-billing', views.update_billing), path('confirm-billing', views.confirm_billing), + path('cancel-billing', views.cancel_billing), path('get-billings', views.get_billings), path('get-billing', views.get_billing), path('get-hospital-prices', views.get_hospital_prices), diff --git a/api/contracts/views.py b/api/contracts/views.py index 71927e00d7..5103c2dd86 100644 --- a/api/contracts/views.py +++ b/api/contracts/views.py @@ -19,8 +19,9 @@ def create_billing(request): hospital_id = body.get("hospitalId") date_start = body.get("dateStart") date_end = body.get("dateEnd") + price_id = body.get("priceId") info = body.get("info") - billing_id = BillingRegister.create_billing(company_id, hospital_id, date_start, date_end, info) + billing_id = BillingRegister.create_billing(company_id, hospital_id, date_start, date_end, info, price_id) return JsonResponse({"ok": True, "billingInfo": billing_id}) @@ -33,27 +34,56 @@ def update_billing(request): date_end = body.get("dateEnd") billing_id = body.get("id") info = body.get("info") - billing_info = BillingRegister.update_billing(billing_id, date_start, date_end, info) - type_price = body.get("typeCompany") - data = researches_for_billing(type_price, hospital_id, date_start, date_end) - structure_data = structure_table(data) - return JsonResponse({"ok": True, "billingInfo": billing_info, **structure_data}) + price_id = body.get("priceId") + billing_data = BillingRegister.objects.filter(pk=billing_id).first() + if not billing_data.is_confirmed: + billing_info = BillingRegister.update_billing(billing_id, date_start, date_end, info, price_id) + type_price = body.get("typeCompany") + data = researches_for_billing(type_price, hospital_id, date_start, date_end, price_id, billing_data.is_confirmed, billing_id) + structure_data = structure_table(data) + return JsonResponse({"ok": True, "billingInfo": billing_info, **structure_data}) @login_required @group_required("Счет: проект") def confirm_billing(request): body = json.loads(request.body) - billing_id = body.get("billingId") - iss_ids = body.get("issIds") - price_id = body.get("priceId") - with transaction.atomic(): - is_confirm_billing = BillingRegister.confirm_billing(billing_id) - set_billing_id_for_iss = Issledovaniya.save_billing(billing_id, iss_ids) - data_confirm_billing = get_confirm_data_for_billing(price_id, billing_id) - raw_document_pk = RawDocumentBillingRegister.create_raw_billing_data(billing_id, data_confirm_billing) + billing_id = body.get("id") + type_price = body.get("typeCompany") + billing_data = BillingRegister.objects.filter(pk=billing_id).first() + if not billing_data.is_confirmed: + hospital_id = billing_data.hospital_id + date_start = billing_data.date_start + date_end = billing_data.date_end + price_id = billing_data.price_id + + data = researches_for_billing(type_price, hospital_id, date_start, date_end, price_id, billing_data.is_confirmed, billing_id) + iss_ids = data["issIds"] + user_who_create = request.user.doctorprofile + + with transaction.atomic(): + is_confirm_billing = BillingRegister.confirm_billing(billing_id, user_who_create) + set_billing_id_for_iss = Issledovaniya.save_billing(billing_id, iss_ids) + data_confirm_billing = get_confirm_data_for_billing(price_id, billing_id) + raw_document_pk = RawDocumentBillingRegister.create_raw_billing_data(billing_id, data_confirm_billing) + structure_data = structure_table(data) + return JsonResponse({"ok": is_confirm_billing and set_billing_id_for_iss and raw_document_pk, **structure_data}) - return JsonResponse({"ok": is_confirm_billing and set_billing_id_for_iss and raw_document_pk}) + +@login_required +@group_required("Счет: проект") +def cancel_billing(request): + body = json.loads(request.body) + billing_id = body.get("id") + billing_data = BillingRegister.objects.filter(pk=billing_id).first() + if billing_data.is_confirmed: + user_who_create = request.user.doctorprofile + with transaction.atomic(): + billing_data.is_confirmed = False + billing_data.who_create = user_who_create + billing_data.save() + Issledovaniya.cancel_billing(billing_id) + return JsonResponse({"ok": True}) @login_required @@ -63,12 +93,14 @@ def get_hospital_prices(request): hospital_id = body.get("hospitalId") date_start = body.get("dateStart") date_end = body.get("dateEnd") - prices = PriceName.get_hospital_many_prices_by_date(hospital_id, date_start, date_end, is_subcontract=True) - prices_data = [{"id": i.pk, "label": i.title} for i in prices] + if not (date_start) or not (date_end): + prices_data = [] + else: + prices = PriceName.get_hospital_many_prices_by_date(hospital_id, date_start, date_end, is_subcontract=True) + prices_data = [{"id": i.pk, "label": i.title} for i in prices] return JsonResponse({"data": prices_data}) - @login_required @group_required("Счет: проект") def change_visibility_research(request): @@ -94,6 +126,6 @@ def get_billing(request): billing_id = request_data.get("billingId") result = BillingRegister.get_billing(billing_id) type_price = request_data.get("typeCompany") - data = researches_for_billing(type_price, result["hospitalId"], result["dateStart"], result["dateEnd"]) + data = researches_for_billing(type_price, result["hospitalId"], result["dateStart"], result["dateEnd"], result["priceId"], result["isConfirmed"], billing_id) structure_data = structure_table(data) return JsonResponse({"result": result, **structure_data}) diff --git a/contracts/admin.py b/contracts/admin.py index 2d026100f6..b2fd135a21 100644 --- a/contracts/admin.py +++ b/contracts/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import PriceName, PriceCoast, Contract, Company, PriceCategory, CompanyDepartment, MedicalExamination, BillingRegister +from .models import PriceName, PriceCoast, Contract, Company, PriceCategory, CompanyDepartment, MedicalExamination, BillingRegister, RawDocumentBillingRegister class ResPriceCoast(admin.ModelAdmin): @@ -95,9 +95,21 @@ class ResMedicalExamination(admin.ModelAdmin): class ResBillingRegister(admin.ModelAdmin): - list_display = ('company', 'hospital',) - list_display_links = ('company', 'hospital',) - list_filter = ('hospital', 'create_at',) + list_display = ( + 'company', + 'hospital', + 'date_start', + 'date_end', + 'price', + ) + list_display_links = ( + 'company', + 'hospital', + ) + list_filter = ( + 'hospital', + 'create_at', + ) admin.site.register(PriceCategory) @@ -108,3 +120,4 @@ class ResBillingRegister(admin.ModelAdmin): admin.site.register(PriceCoast, ResPriceCoast) admin.site.register(MedicalExamination, ResMedicalExamination) admin.site.register(BillingRegister, ResBillingRegister) +admin.site.register(RawDocumentBillingRegister) diff --git a/contracts/models.py b/contracts/models.py index 6cb38bfa5b..c8f0d6243f 100644 --- a/contracts/models.py +++ b/contracts/models.py @@ -364,33 +364,35 @@ class BillingRegister(models.Model): date_end = models.DateField(help_text="Дата окончания периода", default=None, blank=True, null=True, db_index=True) info = models.CharField(max_length=128, help_text="Информация по счет", default=None, blank=True, null=True) is_confirmed = models.BooleanField(default=False, help_text="Сформирован счет") - price_name = models.ForeignKey(PriceName, on_delete=models.DO_NOTHING, default=None, blank=True, null=True, db_index=True) + price = models.ForeignKey(PriceName, on_delete=models.DO_NOTHING, default=None, blank=True, null=True, db_index=True) def __str__(self): - return f"{self.company} - {self.date_start} - {self.date_end}" + return f"{self.company} - {self.date_start} - {self.date_end} - {self.price}" @staticmethod - def update_billing(billing_id, date_start, date_end, info): + def update_billing(billing_id, date_start, date_end, info, price_id): current_billing = BillingRegister.objects.filter(id=billing_id).first() if current_billing: current_billing.date_start = date_start current_billing.date_end = date_end current_billing.info = info + current_billing.price_id = price_id current_billing.save() return info else: return False @staticmethod - def create_billing(company_id, hospital_id, date_start, date_end, info): - current_billing = BillingRegister(hospital_id=hospital_id, company_id=company_id, date_start=date_start, date_end=date_end, info=info) + def create_billing(company_id, hospital_id, date_start, date_end, info, price_id): + current_billing = BillingRegister(hospital_id=hospital_id, company_id=company_id, date_start=date_start, date_end=date_end, info=info, price_id=price_id) current_billing.save() return current_billing.pk @staticmethod - def confirm_billing(billing_id): + def confirm_billing(billing_id, user_who_create): current_billing = BillingRegister.objects.filter(id=billing_id).first() current_billing.is_confirmed = True + current_billing.who_create = user_who_create current_billing.save() return True @@ -399,13 +401,17 @@ def get_billings(hospital_id=None, company_id=None): if hospital_id: billings = BillingRegister.objects.filter(hospital_id=hospital_id).select_related("hospital") result = [ - {"id": billing.pk, "label": f"{billing.hospital.short_title}-{billing.date_start.strftime('%d.%m.%Y')}-{billing.date_end.strftime('%d.%m.%Y')}"} for billing in billings + { + "id": billing.pk, + "label": f"{billing.date_start.strftime('%d.%m.%Y')} " + f" - {billing.date_end.strftime('%d.%m.%Y')}____Прайс {billing.price.title if billing.price else ''}_____{'Закрыт' if billing.is_confirmed else 'Проект'}", + } + for billing in billings ] else: billings = BillingRegister.objects.filter(company_id=company_id).select_related("company") result = [ - {"id": billing.pk, "label": f"{billing.info}-{billing.company.short_title}-{billing.date_start.strftime('%d.%m.%Y')}-{billing.date_end.strftime('%d.%m.%Y')}"} - for billing in billings + {"id": billing.pk, "label": f"{billing.info}-{billing.price.title}-{billing.date_start.strftime('%d.%m.%Y')}-{billing.date_end.strftime('%d.%m.%Y')}"} for billing in billings ] return result @@ -420,6 +426,7 @@ def as_json(self): "dateEnd": self.date_end, "info": self.info, "isConfirmed": self.is_confirmed, + "priceId": self.price_id, } return result @@ -442,7 +449,8 @@ class RawDocumentBillingRegister(models.Model): @staticmethod def create_raw_billing_data(billing_id, raw_data): - raw_data_billing = RawDocumentBillingRegister(billing_id=billing_id, raw_data=raw_data).save() + raw_data_billing = RawDocumentBillingRegister(billing_id=billing_id, raw_data=raw_data) + raw_data_billing.save() return raw_data_billing.pk class Meta: diff --git a/contracts/sql_func.py b/contracts/sql_func.py index 0e8ccba0cb..876ea8f885 100644 --- a/contracts/sql_func.py +++ b/contracts/sql_func.py @@ -1,5 +1,7 @@ import datetime from django.db import connection + +from laboratory.settings import TIME_ZONE from utils.db import namedtuplefetchall @@ -64,7 +66,7 @@ def get_research_coast_by_prce(price_id): return rows -def get_data_for_conform_billing(billing_id): +def get_data_for_confirm_billing(billing_id): with connection.cursor() as cursor: cursor.execute( """ @@ -73,6 +75,8 @@ def get_data_for_conform_billing(billing_id): directions_issledovaniya.id as iss_id, directions_issledovaniya.research_id, directory_researches.title as research_title, + directory_researches.internal_code as internal_code, + directory_researches.code as code_nmu, to_char(directions_issledovaniya.time_confirmation AT TIME ZONE %(tz)s, 'DD.MM.YYYY') AS date_confirm, directions_issledovaniya.time_confirmation, directions_napravleniya.client_id, @@ -100,13 +104,12 @@ def get_data_for_conform_billing(billing_id): ON ci.id = cc.individual_id WHERE - directions_issledovaniya.billing_id = %(billing)s and - directions_issledovaniya.id in %(iss_ids)s + directions_issledovaniya.billing_id = %(billing_id)s ORDER BY directions_napravleniya.client_id, directions_issledovaniya.time_confirmation """, - params={'billing_id': billing_id}, + params={'billing_id': billing_id, 'tz': TIME_ZONE}, ) rows = namedtuplefetchall(cursor) return rows diff --git a/directions/models.py b/directions/models.py index 5399b04e67..62fce3bea4 100644 --- a/directions/models.py +++ b/directions/models.py @@ -2316,13 +2316,20 @@ class Issledovaniya(models.Model): billing = models.ForeignKey(contracts.BillingRegister, db_index=True, blank=True, null=True, default=None, help_text="Принадлежит счету", on_delete=models.SET_NULL) @staticmethod - def save_billing(iss_ids, billing_id): - iss = Issledovaniya.objects.filter(id_in=iss_ids) + def save_billing(billing_id, iss_ids): + iss = Issledovaniya.objects.filter(pk__in=iss_ids) for i in iss: i.billing_id = billing_id i.save() return True + @staticmethod + def cancel_billing(billing_id): + iss = Issledovaniya.objects.filter(billing_id=billing_id) + for i in iss: + i.billing_id = None + i.save() + return True @property def time_save_local(self): @@ -2385,7 +2392,7 @@ def gen_after_confirm(self, user: User): ) def __str__(self): - return f"{self.pk} - {self.napravleniye.pk}-{self.napravleniye.client.get_fio_w_card()}" + return f"{self.pk} - {self.napravleniye}" def is_get_material(self): """ diff --git a/forms/xlsx/billing/billing_func.py b/forms/xlsx/billing/billing_func.py new file mode 100644 index 0000000000..3f2fd7ccdc --- /dev/null +++ b/forms/xlsx/billing/billing_func.py @@ -0,0 +1,73 @@ +import os +from openpyxl.styles import Border, Side, Alignment, Font, NamedStyle +from openpyxl.utils import get_column_letter +from openpyxl.drawing.image import Image +from laboratory.settings import BASE_DIR + + +def billing_base(ws1): + style_border = NamedStyle(name="style_border_ca") + bd = Side(style="thin", color="000000") + style_border.border = Border(left=bd, top=bd, right=bd, bottom=bd) + style_border.font = Font(bold=True, size=8) + style_border.alignment = Alignment(wrap_text=True, horizontal="left", vertical="center") + + columns = [ + ("№", 5), + ("Пациент", 20), + ("Дата рожд.", 7), + ("Дата вып.", 7), + ("Код", 8), + ("Код НМУ", 11), + ("Наименование услуги", 19), + ("Лаб.номер", 13), + ("Цена", 5), + ("Кол", 5), + ("Стоимость, руб", 7), + ] + + row = 13 + for idx, column in enumerate(columns, 1): + ws1.cell(row=row, column=idx).value = column[0] + ws1.column_dimensions[get_column_letter(idx)].width = column[1] + ws1.cell(row=row, column=idx).style = style_border + return ws1 + + +def fill_billing(ws1, data, row=14): + style_border1 = NamedStyle(name="style_border1") + bd = Side(style="thin", color="000000") + style_border1.border = Border(left=bd, top=bd, right=bd, bottom=bd) + style_border1.font = Font(bold=False, size=8) + style_border1.alignment = Alignment(wrap_text=True, horizontal="left", vertical="center") + + style_border2 = NamedStyle(name="style_border2") + bd = Side(style="thin", color="000000") + style_border2.border = Border(left=bd, top=bd, right=bd, bottom=bd) + style_border2.font = Font(bold=False, size=10) + style_border2.alignment = Alignment(wrap_text=True, horizontal="center", vertical="center") + logo = Image(os.path.join(BASE_DIR, "forms", "xlsx", "media", "logo.png")) + logo.height = 130 + logo.width = 920 + ws1.add_image(logo, "A1") + ws1.merge_cells("A9:L11") + megre_cell = ws1["A9"] + megre_cell.value = "Реестр № 1YYYY от 00 марта 2024 года \n оказанных медицинских услуг по договору №00 - 00/00/2024 \n с 00.00.00 по 00.00.00" + megre_cell.style = style_border2 + r = row + for val in data: + ws1.cell(row=r, column=1).value = val.get("serialNumber") + ws1.cell(row=r, column=2).value = val.get("patientFio") + ws1.cell(row=r, column=3).value = val.get("patientBirthDay") + ws1.cell(row=r, column=4).value = val.get("executeDate") + ws1.cell(row=r, column=5).value = val.get("internalId") + ws1.cell(row=r, column=6).value = val.get("codeNMU") + ws1.cell(row=r, column=7).value = val.get("researchTitle") + ws1.cell(row=r, column=8).value = val.get("tubeNumber") + ws1.cell(row=r, column=9).value = val.get("coast") + ws1.cell(row=r, column=10).value = 1 + ws1.cell(row=r, column=11).value = val.get("summ") + for i in range(1, 12): + ws1.cell(row=r, column=i).style = style_border1 + r += 1 + return ws1 diff --git a/forms/xlsx/forms101.py b/forms/xlsx/forms101.py new file mode 100644 index 0000000000..e46e484e52 --- /dev/null +++ b/forms/xlsx/forms101.py @@ -0,0 +1,20 @@ +from openpyxl import Workbook +import openpyxl +from api.contracts.func import get_confirm_data_for_billing, structure_table +from contracts.models import BillingRegister +from forms.xlsx.billing import billing_func + + +def form_01(request_data) -> Workbook: + billing_id = request_data.get("billingId") + wb = openpyxl.Workbook() + wb.remove(wb.get_sheet_by_name("Sheet")) + ws = wb.create_sheet("Счет") + ws.set_printer_settings("9", "landscape") + + billing_data = BillingRegister.objects.filter(pk=billing_id).first() + data_confirm_billing = get_confirm_data_for_billing(billing_data.price_id, billing_id) + structure_data = structure_table(data_confirm_billing) + ws = billing_func.billing_base(ws) + ws = billing_func.fill_billing(ws, structure_data.get("tableData")) + return wb diff --git a/l2-frontend/src/pages/Billing/index.vue b/l2-frontend/src/pages/Billing/index.vue index 35d7b42a54..086a303172 100644 --- a/l2-frontend/src/pages/Billing/index.vue +++ b/l2-frontend/src/pages/Billing/index.vue @@ -70,20 +70,37 @@
+ +