14
14
15
15
from odoo import _ , api , fields , models
16
16
from odoo .exceptions import UserError
17
+ from odoo .osv .expression import AND , OR
17
18
from odoo .tools import config , float_compare , float_is_zero , float_round
18
19
from odoo .tools .misc import format_amount
19
20
20
21
logger = logging .getLogger (__name__ )
21
22
22
23
24
+ try :
25
+ from facturx import get_xml_from_pdf
26
+ except ImportError :
27
+ logger .debug ("Cannot import facturx" )
28
+
29
+
30
+ def get_wildcard_string (val ):
31
+ if val and val [- 1 ] != "%" :
32
+ val += "%"
33
+ return val
34
+
35
+
23
36
class AccountInvoiceImport (models .TransientModel ):
24
37
_name = "account.invoice.import"
25
38
_inherit = ["business.document.import" , "mail.thread" ]
@@ -83,6 +96,16 @@ def default_get(self, fields_list):
83
96
def parse_xml_invoice (self , xml_root ):
84
97
return False
85
98
99
+ @api .model
100
+ def get_xml_files_from_pdf (self , file_data ):
101
+ """
102
+ Overwrite the original function to use the facturx libraray to extract
103
+ xml from pdf
104
+ """
105
+ data = get_xml_from_pdf (pdf_file = file_data , check_xsd = False )
106
+ xml_root = etree .fromstring (data [1 ])
107
+ return {data [0 ]: xml_root }
108
+
86
109
@api .model
87
110
def parse_pdf_invoice (self , file_data ):
88
111
"""This method must be inherited by additional modules with
@@ -254,7 +277,9 @@ def _prepare_create_invoice_vals(self, parsed_inv, import_config):
254
277
assert parsed_inv .get ("pre-processed" ), "pre-processing not done"
255
278
amo = self .env ["account.move" ]
256
279
company = (
257
- self .env ["res.company" ].browse (self .env .context .get ("force_company" ))
280
+ self .env ["res.company" ].browse (
281
+ parsed_inv .get ("company_id" ) or self .env .context .get ("force_company" )
282
+ )
258
283
or self .env .company
259
284
)
260
285
vals = {
@@ -267,6 +292,8 @@ def _prepare_create_invoice_vals(self, parsed_inv, import_config):
267
292
"invoice_payment_ref" : parsed_inv .get ("payment_reference" ),
268
293
"invoice_line_ids" : [],
269
294
}
295
+ if parsed_inv .get ("operating_unit_id" ):
296
+ vals ["operating_unit_id" ] = parsed_inv .get ("operating_unit_id" )
270
297
if parsed_inv ["type" ] in ("out_invoice" , "out_refund" ):
271
298
partner_type = "customer"
272
299
else :
@@ -525,7 +552,9 @@ def parse_invoice(self, invoice_file_b64, invoice_filename, email_from=None):
525
552
parsed_inv ["partner" ]["name" ] = partner_name
526
553
# pre_process_parsed_inv() will be called again a second time,
527
554
# but it's OK
528
- pp_parsed_inv = self .pre_process_parsed_inv (parsed_inv )
555
+ pp_parsed_inv = self .with_context (
556
+ edi_skip_company_check = True
557
+ ).pre_process_parsed_inv (parsed_inv )
529
558
return pp_parsed_inv
530
559
531
560
@api .model
@@ -797,14 +826,109 @@ def new_partner(self):
797
826
# If you have an idea on how to fix this problem, please tell me!
798
827
return action
799
828
829
+ @api .model
830
+ def _match_product_search (self , product_dict ):
831
+ """
832
+ Extend the product search function to find products with additional
833
+ parameters.
834
+ """
835
+ default_code = product_dict .get ("code" )
836
+ barcode = product_dict .get ("barcode" )
837
+ ProductProduct = self .env ["product.product" ]
838
+ args = []
839
+ if default_code :
840
+ args += ProductProduct ._get_e_invoice_default_code_search_args (
841
+ default_code , get_wildcard_string (default_code )
842
+ )
843
+ if barcode :
844
+ args += ProductProduct ._get_e_invoice_barcode_search_args (
845
+ barcode , get_wildcard_string (barcode )
846
+ )
847
+ if args :
848
+ domain = AND (
849
+ [
850
+ OR ([arg ] for arg in args ),
851
+ [("company_id" , "in" , [False , self .env .company .id ])],
852
+ ]
853
+ )
854
+ product_variant_id = ProductProduct .search (domain , limit = 1 )
855
+ if product_variant_id :
856
+ return product_variant_id
857
+ return super ()._match_product_search (product_dict = product_dict )
858
+
859
+ @api .model
860
+ def _hook_match_partner (self , partner_dict , chatter_msg , domain , order ):
861
+ """
862
+ Custom partner search function to find partners with additional
863
+ parameters.
864
+ """
865
+ gln = partner_dict .get ("gln" )
866
+ vat = partner_dict .get ("vat" )
867
+ tax_number = partner_dict .get ("tax_number" )
868
+ ResPartner = self .env ["res.partner" ]
869
+ args = []
870
+ if gln :
871
+ args += ResPartner ._get_e_invoice_gln_search_args (
872
+ gln , get_wildcard_string (gln )
873
+ )
874
+ if vat :
875
+ args += ResPartner ._get_e_invoice_vat_search_args (
876
+ vat , get_wildcard_string (vat )
877
+ )
878
+ if tax_number :
879
+ args += ResPartner ._get_e_invoice_tax_number_search_args (
880
+ tax_number , get_wildcard_string (tax_number )
881
+ )
882
+ if args :
883
+ domain = AND (
884
+ [
885
+ OR ([arg ] for arg in args ),
886
+ [("company_id" , "in" , [False , self .env .company .id ])],
887
+ ]
888
+ )
889
+ partner_id = ResPartner .search (domain , limit = 1 )
890
+ if partner_id :
891
+ return partner_id
892
+ return super ()._hook_match_partner (
893
+ partner_dict = partner_dict ,
894
+ chatter_msg = chatter_msg ,
895
+ domain = domain ,
896
+ order = order ,
897
+ )
898
+
899
+ def _get_operating_unit (self , parsed_inv ):
900
+ """
901
+ Find the buyer party partner and get the operating unit from it
902
+ """
903
+ OperatingUnit = self .env ["operating.unit" ]
904
+ try :
905
+ partner_id = self ._match_partner (
906
+ parsed_inv ["company" ], parsed_inv ["chatter_msg" ], raise_exception = False
907
+ )
908
+ if partner_id :
909
+ return self .env ["operating.unit" ].search (
910
+ [("partner_id" , "=" , partner_id .id )], limit = 1
911
+ )
912
+ except Exception :
913
+ ...
914
+ return OperatingUnit
915
+
800
916
def import_invoice (self ):
801
917
"""Method called by the button of the wizard
802
918
(import step AND config step)"""
803
919
self .ensure_one ()
804
920
amo = self .env ["account.move" ]
805
921
aiico = self .env ["account.invoice.import.config" ]
806
- company_id = self .env .context .get ("force_company" ) or self .env .company .id
807
922
parsed_inv = self .get_parsed_invoice ()
923
+ operating_unit_id = self ._get_operating_unit (parsed_inv )
924
+ if operating_unit_id :
925
+ parsed_inv ["operating_unit_id" ] = operating_unit_id .id
926
+ company_id = (
927
+ operating_unit_id .company_id .id
928
+ or self .env .context .get ("force_company" )
929
+ or self .env .company .id
930
+ )
931
+ parsed_inv ["company_id" ] = company_id
808
932
if not self .partner_id :
809
933
if parsed_inv .get ("partner" ):
810
934
try :
0 commit comments