From 5f6d41a871fbc7d0f67be7f0a2824201d10c84aa Mon Sep 17 00:00:00 2001 From: Marius Robert Macamete Date: Sat, 8 Nov 2025 20:50:29 +0200 Subject: [PATCH] add modul inventory --- UI_V2/admin/dashboard.py | 12 +- .../goods_reception.cpython-313.pyc | Bin 0 -> 1685 bytes .../__pycache__/inventory.cpython-313.pyc | Bin 0 -> 3832 bytes .../__pycache__/providers.cpython-313.pyc | Bin 0 -> 17949 bytes UI_V2/admin/inventory/consumption.py | 0 UI_V2/admin/inventory/goods_reception.py | 25 ++ UI_V2/admin/inventory/inventory.py | 64 ++++ UI_V2/admin/inventory/providers.py | 301 ++++++++++++++++++ UI_V2/admin/inventory/stocks.py | 0 UI_V2/admin/settings.py | 4 +- UI_V2/dbActions/providers.py | 158 +++++++++ 11 files changed, 561 insertions(+), 3 deletions(-) create mode 100644 UI_V2/admin/inventory/__pycache__/goods_reception.cpython-313.pyc create mode 100644 UI_V2/admin/inventory/__pycache__/inventory.cpython-313.pyc create mode 100644 UI_V2/admin/inventory/__pycache__/providers.cpython-313.pyc create mode 100644 UI_V2/admin/inventory/consumption.py create mode 100644 UI_V2/admin/inventory/goods_reception.py create mode 100644 UI_V2/admin/inventory/inventory.py create mode 100644 UI_V2/admin/inventory/providers.py create mode 100644 UI_V2/admin/inventory/stocks.py create mode 100644 UI_V2/dbActions/providers.py diff --git a/UI_V2/admin/dashboard.py b/UI_V2/admin/dashboard.py index 2ae3d68..038084b 100644 --- a/UI_V2/admin/dashboard.py +++ b/UI_V2/admin/dashboard.py @@ -6,6 +6,7 @@ from admin.orders import OrdersPage from admin.clients import Clients from admin.fidelity_cards import FidelityCards from admin.settings import Settings +from admin.inventory.inventory import Inventory class Dashboard: def __init__(self, page: ft.Page): @@ -59,6 +60,11 @@ class Dashboard: selected_icon=ft.Icon(ft.Icons.CARD_GIFTCARD), label_content=ft.Text("Card de\nfidelitate"), ), + ft.NavigationRailDestination( + icon=ft.Icons.INVENTORY_2_OUTLINED, + selected_icon=ft.Icon(ft.Icons.INVENTORY_2), + label_content=ft.Text("Inventar"), + ), ft.NavigationRailDestination( icon=ft.Icons.SETTINGS_APPLICATIONS_OUTLINED, selected_icon=ft.Icon(ft.Icons.SETTINGS_APPLICATIONS), @@ -103,10 +109,14 @@ class Dashboard: self.placeholder.content = self.fidelity_cards.build() self.placeholder.update() case 7: + self.inventory = Inventory(self.page, self) + self.placeholder.content = self.inventory.build() + self.placeholder.update() + case 8: self.settings = Settings(self.page, self) self.placeholder.content = self.settings.build() self.placeholder.update() - case 8: + case 9: self.page.client_storage.clear() self.page.session.clear() self.page.go('/') diff --git a/UI_V2/admin/inventory/__pycache__/goods_reception.cpython-313.pyc b/UI_V2/admin/inventory/__pycache__/goods_reception.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3594402616a157cef1f2454f2dcdab3ada6f0b7d GIT binary patch literal 1685 zcmZuxO=ufe5PtikwWLV0l{&6t+*T+lbT8Qwl7OKp$d+wH;~#e8Sfvh+)$U5(bhYce zeaas>_|!v42^2)zT+(ZffkG%0dhIbfIlTDR^x#WTql8>LZ}o#Lb&zJ~&CHwk&Age{ zNvD$t=pS#={aZxnFTUuL+!H!E5Sqw9hVT_4!Ys-oL!3i~bP;xNB4SNY^8vL5Qt=mJF*^~-FNPOFNlUThi=G3G2}T!CX5*HxS^0lZ9!3nv0E=N*)ITiTWv~66WKDIp9`j&k%0%FvG*C~tv12FLvnFPriTmUT6 z@Q(o80&Nq01IsSy!!Ucg{IH!P9-(7)ev>0~%+3=XA?R#j2*LmKr_ReTLI(8gf;6-* zGvWYCh%66zOpSZ!C&zVLNS_|p8nFdQ6NjSBjQi-b<2plG5H;aquloJ(S)@*^-^=u7 z%E_&nq-q{@ow#Ul9t zP_XP8L@C^H!$SWAmNqsEOUrn1`Rexa^13QSy&CewdVLzJz>wK&dZalcEx*BVAJ{%R zoXkGD|KR>%D)XrHp!9lr=Es#ER$kA4{ABg<>Wi}%e%JrF{@e9~%NwoB8!xVvTk~HZ zg01wp^vmwA`t$O$^7EZ%JAW1ru9z+O%~#qn>Ga&&I6Cv`LH<%Jf9W7!Y~_ppo={HB zw553VWJgM-GaV^4m29I_A{h+>JUN4>Bzjra)g+&BAD#`E@g&Cez;1Y4PGNkrVR}8w zB*s;jgw%r)`vJz}BS?wKoBTE5LlqT|s9bpp5fO%Hwh5o7 zi1Bd@=Yf5P+M*OY^OOE$`{(Vq2*fu@A(nopq+?z1k-I7}x#~GI0?>_eJTi-a(aqsY davq}cYYKUPwIx9iUZL!Jc}7USLBJw3{{ha;WK;kE literal 0 HcmV?d00001 diff --git a/UI_V2/admin/inventory/__pycache__/inventory.cpython-313.pyc b/UI_V2/admin/inventory/__pycache__/inventory.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a9ca72473a0cba2029549a5d299ecc17cdc32df GIT binary patch literal 3832 zcmeGfTWlLeaL;$P&u*TsThh?FCMlFllUS-KA{A*#lQv1yrtMu`RYOmg^ToN=zB7C0 zJ|YDDLIoiqAyu^S(ch+gginx=5E2qaLLyd+Y%QsTL_f%%(-a}`#q6E!IIg9(5=eZo zvgdYoc4ueju`|0?Umrx!dNYkWy9uG+C{k)%v9mS+ooh%!5;KA@17FXG=O~NWC>>)* zxT9X|b^6?h@2DU9qo@V7A<5f{B;P)d%LVfZM)0ptWK>`Xe-fMVjA~oZ4?zEd9@j8M z8U{@>Zi$+zrET3bRCl!ti>%Pv5a8F)v?C1mNDO8r&on1GN2y$Z&?_E^ZAIre?31`w zg#A<~%u7Ci0m+Yp30?@0z_4*aGi(!IUh%h+YjIxnrcdxiBr)e zQ$o&oOTB%?&Nxbz`6SQ+Gb(U605lSaE7shMso*%K6G&s)RfwEY4A>nDEa5CIIqS^E zbuh)E^PDe;tU#Prg!*L&UR%Y>I@-Oz1WCZV!ox=UkzD#=y=S5Q9O@?jvqt?k2x z<(<1fo4?Ba%x_-<3Q|jkq6k%qqq<+Aa}Av-D{CBymGgi~8;q9x&K)R@?klR%@Qiyz zDnwOVS9q=UB40Hf&}7+IwfC&GMy!9FPif~UN+1j|gakjPM_9KU@y>uP;$%}gsi@kV znFL=ae$_N=@H*nlq~nUM2`p}aRfN$<0DQp>h?325BPDG$4Y^E`XKX`Ole&7IMAyw! zdxqmagTUenS`P2H9>1yI&~JqoBMXr)!*|06t_Jd5uP(|9^4+cjSGkWG-fzh9ZCSqU z9^aAY>(=ocFJyV)XMPV30k8k9OdV+5$~a8XEfmoBz|R3F8Wp!dpLi4WYTIbi5E#rE zt}y5J4d$$(HUlT?2mml;Q{=jR^YV?$w{|UdFLZyo>u%G*tKNLq-o-NuXFh-P87x_j zN#IKl;KVBrP7Lu1sM~5qYg;9qI(=2!K&N+WRog(X5u+REHExRy^e63KBRyigyCF@Gc~TM_1yoz2G670fh$CCi=WKA9kyX z6r{1}kqkEUc@yg^G#&&GZif%?UDWi%oJ|5{GG(Dd?jt;0eNO&@sxLeT3+EvrDoI&M z>Is9gT%iFAjA#@Pe_Dyhbt54#4nE&dED^QnaRtvR#Or)k=pC@~7k~u(p%o5}>A%Bu zCisZoN-HXGAVHilELk-(kbHwF<&vyjauRV!or5ebD^?l`C>bkIe-fW|DXkcB;=QQH z?KvStJhO0^ek!SMKoHVG@vuB5j`xoc zZVYyV5#TWCs)jps;@AN39m?1?Eb$*XAx`#*1DM7u3H4*svidIRR$oagu;t;=vBM%T zA3ZrfhG~3)Qs_lxQJY1bTER(1q;WlyI28!hq%{w-AbB)4fAsbTZ!d?pelq;=@B{da zd_3}Cd*tTer-REccP!T3u3PTxUL3wX`~W_Kw+Futebe$)ORncww&&QAG?DF`q;w!G zy>fKvlyqwm|U-z?GvlvQwW1w6pCH;dk*^|m)NH3% zmTTb7-g^^Mxd}Bpq2?y$vheHFOJXIyJM{g~w?nysvFyOulC0+B3t9MeUVH|z3Ok

?QCz0jU--<5BFDZi&Xzq36bX z$wvsf4}+|?(*b`3JG|~0oHg)x;%1YY?aC2~&-AJE)n;`UUo)2bxY_2sH@fxGdxMhQ z0@taO$w Sb|3BkliSY(A0hzG;=ci@QRjjH literal 0 HcmV?d00001 diff --git a/UI_V2/admin/inventory/__pycache__/providers.cpython-313.pyc b/UI_V2/admin/inventory/__pycache__/providers.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..568a7ba327bcf9aef1e2edc3b977ac79f68f9a34 GIT binary patch literal 17949 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 R9lxl6S literal 0 HcmV?d00001 diff --git a/UI_V2/admin/inventory/consumption.py b/UI_V2/admin/inventory/consumption.py new file mode 100644 index 0000000..e69de29 diff --git a/UI_V2/admin/inventory/goods_reception.py b/UI_V2/admin/inventory/goods_reception.py new file mode 100644 index 0000000..53fe625 --- /dev/null +++ b/UI_V2/admin/inventory/goods_reception.py @@ -0,0 +1,25 @@ +import flet as ft + +class GoodsReception: + def __init__(self, page: ft.Page, dashboard, inventory): + self.page = page + self.dashboard = dashboard + self.inventory = inventory + + def on_add_btn_click(self, e): + pass + + def build(self): + return ft.Container( + ft.Column( + [ + ft.Row( + [ + ft.Text("Receptie Marfa", weight=ft.FontWeight.BOLD, size=18), + ft.Button("Adauga", icon=ft.Icons.ADD, on_click=self.on_add_btn_click) + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN + ) + ] + ) + ) \ No newline at end of file diff --git a/UI_V2/admin/inventory/inventory.py b/UI_V2/admin/inventory/inventory.py new file mode 100644 index 0000000..1768c6c --- /dev/null +++ b/UI_V2/admin/inventory/inventory.py @@ -0,0 +1,64 @@ +import flet as ft +from dbActions.products import Products +from admin.inventory.providers import Providers +from admin.inventory.goods_reception import GoodsReception + +class Inventory: + def __init__(self, page: ft.Page, dashboard): + self.page = page + self.dashboard = dashboard + self.product_manager = Products() + + def on_providers_btn_click(self, e): + providers = Providers(self.page, self.dashboard, self) + self.dashboard.placeholder.content = providers.build() + self.dashboard.placeholder.update() + + def on_goods_btn_click(self, e): + goods = GoodsReception(self.page, self.dashboard, self) + self.dashboard.placeholder.content = goods.build() + self.dashboard.placeholder.update() + + def build(self): + return ft.Container( + content=ft.Column( + [ + ft.GridView( + [ + ft.Card( + content=ft.Container( + content=ft.Column( + [ + ft.Icon(name=ft.Icons.FIRE_TRUCK, size=100), + ft.Text("Management Furnizori", size=16, weight=ft.FontWeight.BOLD), + ft.Button("Furnizori", icon=ft.Icons.FORWARD, on_click=self.on_providers_btn_click) + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER + ), + padding=10 + ) + ), + ft.Card( + content=ft.Container( + content=ft.Column( + [ + ft.Icon(name=ft.Icons.INPUT, size=100), + ft.Text("Receptie Marfa", size=16, weight=ft.FontWeight.BOLD), + ft.Button("Marfa", icon=ft.Icons.FORWARD, on_click=self.on_goods_btn_click) + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER + ), + padding=10 + ) + ) + ], + spacing=10, + runs_count=4, + max_extent=250, + child_aspect_ratio=1.0, + expand=True, + width=1000 + ) + ] + ) + ) \ No newline at end of file diff --git a/UI_V2/admin/inventory/providers.py b/UI_V2/admin/inventory/providers.py new file mode 100644 index 0000000..b428714 --- /dev/null +++ b/UI_V2/admin/inventory/providers.py @@ -0,0 +1,301 @@ +import flet as ft +from dbActions.providers import Providers as DBProviders + +class Providers: + def __init__(self, page: ft.Page, dashboard, inventory): + self.page = page + self.dashboard = dashboard + self.inventory = inventory + self.providers_manager = DBProviders() + + self.provider_name = ft.TextField(label="Denumire") + self.provider_vat = ft.TextField(label="CUI") + self.provider_register_number = ft.TextField(label="Numar de inregistrare") + self.provider_address = ft.TextField(label = "Sediu") + self.contact_name = ft.TextField(label="Nume si prenume") + self.contact_number = ft.TextField(label="Telefon") + self.contact_email = ft.TextField(label="E-mail") + self.add_error_message = ft.Text("",color=ft.Colors.RED) + self.status = ft.RadioGroup( + content=ft.Row( + [ + ft.Radio(value="Activ", label="Activ"), + ft.Radio(value="Inactiv", label="Inactiv"), + ], + alignment=ft.MainAxisAlignment.START + ) + ) + self.status_group = ft.Row( + [ + ft.Text("Status: ", weight=ft.FontWeight.BOLD), + self.status + ] + ) + + + self.add_dialog = ft.AlertDialog( + title=ft.Text("Adauga furnizor"), + content=ft.Column( + [ + ft.Text("Furnizor", size=16, weight=ft.FontWeight.BOLD), + self.provider_name, + self.provider_vat, + self.provider_register_number, + self.provider_address, + ft.Text("Persoana de contact", size=16, weight=ft.FontWeight.BOLD), + self.contact_name, + self.contact_number, + self.contact_email, + self.add_error_message + ], + width=400, + height=500 + ), + actions=[ + ft.FilledButton("Salveaza", on_click=self.on_save_btn_click), + ft.Button("Cancel", on_click=self.on_cancel_btn_click) + ] + ) + + self.all_providers = self.providers_manager.get_all_providers() + self.providers_list = ft.ListView( + controls=self.create_list(self.all_providers, self.view_provider, self.edit_provider, self.delete_provider), + spacing=10, + expand=True + ) + + self.delete_dialog = ft.AlertDialog( + title=ft.Text("Stergeti furnizorul?"), + actions = [ + ft.FilledButton("Da", on_click=self.on_delete_btn_click), + ft.Button("Nu", on_click=self.on_cancel_delete_btn_click) + ] + ) + + self.selected_provider_id = None + + self.search = ft.TextField(label="Cauta", on_submit=self.on_search_btn_click, expand=True) + + self.view_provider_name = ft.Text(value="Denumire") + self.view_provider_vat = ft.Text(value="CUI") + self.view_provider_register_number = ft.Text(value="Numar de inregistrare") + self.view_provider_address = ft.Text(value = "Sediu") + self.view_contact_name = ft.Text(value="Nume si prenume") + self.view_contact_number = ft.Text(value="Telefon") + self.view_contact_email = ft.Text(value="E-mail") + self.view_created_date = ft.Text(value="Data creare") + self.view_status = ft.Text(value="Status") + + self.view_dialog = ft.AlertDialog( + title=self.view_provider_name, + content=ft.Column( + [ + self.view_provider_vat, + self.view_provider_register_number, + self.view_provider_address, + ft.Text(), + ft.Text("Persoana de contact", weight=ft.FontWeight.BOLD), + self.view_contact_name, + self.view_contact_number, + self.view_contact_email, + ft.Text(), + self.view_created_date, + self.view_status + ], + width=400, + height=300 + ), + actions=[ft.Button("Close", on_click=self.on_close_btn_click)] + ) + + self.is_editing = None + + def on_delete_btn_click(self, e): + self.providers_manager.remove_provider(self.selected_provider_id) + self.selected_provider_id = None + self.page.close(self.delete_dialog) + + self.all_providers = self.providers_manager.get_all_providers() + self.providers_list.controls=self.create_list(self.all_providers, self.view_provider, self.edit_provider, self.delete_provider) + self.providers_list.update() + + def on_cancel_delete_btn_click(self, e): + self.selected_provider_id = None + self.page.close(self.delete_dialog) + + def view_provider(self, item): + self.view_provider_name.value = item['provider_name'] + self.view_provider_vat.value = 'CUI: ' + item['provider_vat'] + self.view_provider_register_number.value = "Numar de inregistrare: "+item['provider_register_number'] + self.view_provider_address.value = "Sediu: " + item['provider_address'] + self.view_contact_name.value = "Nume si prenume: " + item['contact_name'] + self.view_contact_number.value = "Telefon: " + item['contact_number'] + self.view_contact_email.value = "E-mail: " + item['contact_email'] + self.view_created_date.value = "Creat la: " + item['created_at'] + self.view_status.value = "Status: " + item['status'] + self.page.open(self.view_dialog) + + def on_close_btn_click(self, e): + self.page.close(self.view_dialog) + + + def delete_provider(self, id): + print("Delete ", id) + self.selected_provider_id = id + self.page.open(self.delete_dialog) + + def on_search_btn_click(self, e): + search = self.search.value + buffer = [] + for provider in self.all_providers: + if search.lower() in provider['provider_name'].lower(): + buffer.append(provider) + + self.providers_list.controls=self.create_list(buffer, self.view_provider, self.edit_provider, self.delete_provider) + self.providers_list.update() + + + def create_list(self, items, on_click_handler, on_click_handler2, on_click_handler3): + """Helper to create list items for a column.""" + return [ + ft.Container( + content=ft.Row( + [ + + ft.Row( + [ + ft.Icon(name=ft.Icons.FIRE_TRUCK, size=40), + ft.Column( + [ + ft.Text(value=f"Denumire: {item['provider_name']}", weight=ft.FontWeight.BOLD), + ft.Text(value=f"Status: {item['status']}", size=12) + ] + ) + ] + ), + + ft.Row( + [ + ft.IconButton( + icon=ft.Icons.PREVIEW, + on_click=lambda e, id=item: on_click_handler(id), + ), + ft.IconButton( + icon=ft.Icons.EDIT, + on_click=lambda e, id=item: on_click_handler2(id), + ), + ft.IconButton( + icon=ft.Icons.DELETE, + on_click=lambda e, id=item['id']: on_click_handler3(id), + icon_color=ft.Colors.RED, + ), + ] + ) + + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + ), + width=300, + bgcolor=ft.Colors.BROWN_50, + border = ft.border.all(1, ft.Colors.GREY), + padding=10, + border_radius=8, + ) + for item in items + ] + + def on_add_btn_click(self, e): + self.page.open(self.add_dialog) + + def on_save_btn_click(self, e): + self.page.close(self.add_dialog) + provider = { + 'provider_name':self.provider_name.value, + 'provider_vat':self.provider_vat.value, + 'provider_register_number':self.provider_register_number.value, + 'provider_address':self.provider_address.value, + 'contact_name':self.contact_name.value, + 'contact_number':self.contact_number.value, + 'contact_email':self.contact_email.value, + 'add_error_message':self.add_error_message.value + } + if not self.is_editing: + print('Add provider: ', provider) + self.providers_manager.add_provider(provider) + else: + provider['id'] = self.is_editing + provider['status'] = self.status.value + print('Edit provider: ', provider) + self.providers_manager.update_provider(provider) + self.is_editing = None + + self.all_providers = self.providers_manager.get_all_providers() + self.providers_list.controls=self.create_list(self.all_providers, self.view_provider, self.edit_provider, self.delete_provider) + self.providers_list.update() + + self.reset_fields() + + + + def on_cancel_btn_click(self, e): + self.page.close(self.add_dialog) + self.reset_fields() + + def reset_fields(self): + self.provider_name.value = None + self.provider_name.update() + self.provider_vat.value = None + self.provider_vat.update() + self.provider_register_number.value = None + self.provider_register_number.update() + self.provider_address.value = None + self.provider_address.update() + self.contact_name.value = None + self.contact_name.update() + self.contact_number.value = None + self.contact_number.update() + self.contact_email.value = None + self.contact_email.update() + self.add_error_message.value = None + self.add_error_message.update() + try: + self.add_dialog.content.controls.remove(self.status) + except: + pass + self.add_dialog.content.height = 500 + + def edit_provider(self, item): + self.is_editing = item['id'] + self.provider_name.value = item['provider_name'] + self.provider_vat.value = item['provider_vat'] + self.provider_register_number.value = item['provider_register_number'] + self.provider_address.value = item['provider_address'] + self.contact_name.value = item['contact_name'] + self.contact_number.value = item['contact_number'] + self.contact_email.value = item['contact_email'] + self.status.value = item['status'] + self.add_dialog.content.controls.append(self.status_group) + self.add_dialog.content.height = 600 + self.page.open(self.add_dialog) + + def build(self): + return ft.Container( + ft.Column( + [ + ft.Row( + [ + ft.Text("Furnizori", weight=ft.FontWeight.BOLD, size=18), + ft.Button("Adauga", icon=ft.Icons.ADD, on_click=self.on_add_btn_click) + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN + ), + ft.Row( + [ + self.search, + ft.IconButton(icon=ft.Icons.SEARCH, on_click=self.on_search_btn_click) + ] + ), + self.providers_list + ] + ) + ) \ No newline at end of file diff --git a/UI_V2/admin/inventory/stocks.py b/UI_V2/admin/inventory/stocks.py new file mode 100644 index 0000000..e69de29 diff --git a/UI_V2/admin/settings.py b/UI_V2/admin/settings.py index 7d4cb7d..c59b16c 100644 --- a/UI_V2/admin/settings.py +++ b/UI_V2/admin/settings.py @@ -28,7 +28,7 @@ class Settings: content=ft.Column( [ ft.Icon(name=ft.Icons.DATASET, size=100), - ft.Text("Adauga datele companiei"), + ft.Text("Adauga datele companiei", size=16, weight=ft.FontWeight.BOLD), ft.Button("Adauga", icon=ft.Icons.ADD, on_click=self.on_add_data_btn_click) ], horizontal_alignment=ft.CrossAxisAlignment.CENTER @@ -41,7 +41,7 @@ class Settings: content=ft.Column( [ ft.Icon(name=ft.Icons.POLICY, size=100), - ft.Text("Adauga politicile companiei"), + ft.Text("Adauga politicile companiei", size=16, weight=ft.FontWeight.BOLD), ft.Button("Adauga", icon=ft.Icons.ADD, on_click=self.on_add_policy_btn_click) ], horizontal_alignment=ft.CrossAxisAlignment.CENTER diff --git a/UI_V2/dbActions/providers.py b/UI_V2/dbActions/providers.py new file mode 100644 index 0000000..01f0201 --- /dev/null +++ b/UI_V2/dbActions/providers.py @@ -0,0 +1,158 @@ +import sqlite3 +from typing import Optional + +class Providers: + def __init__(self, db_path="instance/app_database.db"): + self.db_path = db_path + self._create_providers_table() + + def _create_providers_table(self): + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS providers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + provider_name TEXT, + provider_vat TEXT, + provider_register_number TEXT, + provider_address TEXT, + contact_name TEXT, + contact_number TEXT, + contact_email TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + status TEXT NOT NULL DEFAULT 'Activ' + ); + """) + conn.commit() + + def add_provider(self, provider): + try: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + INSERT INTO providers ( + provider_name, + provider_vat, + provider_register_number, + provider_address, + contact_name, + contact_number, + contact_email + ) + VALUES (?, ?, ?, ?, ?, ?, ?) + """, ( + provider['provider_name'], + provider['provider_vat'], + provider['provider_register_number'], + provider['provider_address'], + provider['contact_name'], + provider['contact_number'], + provider['contact_email'] + ) + ) + conn.commit() + return True + except sqlite3.IntegrityError: + return False + + def get_all_providers(self): + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + SELECT * FROM providers + """,) + rows = cursor.fetchall() + result = [] + if rows: + for row in rows: + buffer = { + "id": row[0], + "provider_name": row[1], + "provider_vat": row[2], + "provider_register_number": row[3], + "provider_address": row[4], + "contact_name": row[5], + "contact_number": row[6], + "contact_email": row[7], + "created_at": row[8], + "status": row[9] + } + result.append(buffer) + return result + return [] + + def get_provider(self, id): + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + SELECT * FROM providers WHERE id = ? + """,(id, )) + row = cursor.fetchone() + result = [] + if row: + result = { + "id": row[0], + "provider_name": row[1], + "provider_vat": row[2], + "provider_register_number": row[3], + "provider_address": row[4], + "contact_name": row[5], + "contact_number": row[6], + "contact_email": row[7], + "created_at": row[8], + "status": row[9] + } + return result + return None + + def remove_provider(self, id): + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(''' + DELETE FROM providers WHERE id=?; + ''', (id,)) + conn.commit() + + def update_provider(self, provider): + #try: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + UPDATE providers + SET provider_name = ?, + provider_vat = ?, + provider_register_number = ?, + provider_address = ?, + contact_name = ?, + contact_number = ?, + contact_email = ?, + status = ? + WHERE id = ? + """, (provider['provider_name'], + provider['provider_vat'], + provider['provider_register_number'], + provider['provider_address'], + provider['contact_name'], + provider['contact_number'], + provider['contact_email'], + provider['status'], + provider['id']) + ) + conn.commit() + return True + #except Exception: + # return False + + def deactivate(self, id): + try: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute(""" + UPDATE providers + SET status = ? + WHERE id = ? + """, ('Inactive', id)) + conn.commit() + return True + except Exception: + return False \ No newline at end of file