1111from odoo .tools .safe_eval import datetime , dateutil , safe_eval , time
1212
1313from .accounting_none import AccountingNone
14-
14+ import pprint
1515try :
1616 import itertools .izip as zip
1717except ImportError :
@@ -306,6 +306,8 @@ def do_queries(
306306 date_to ,
307307 additional_move_line_filter = None ,
308308 aml_model = None ,
309+ auto_expand_col_name = None ,
310+ rdi_transformer = lambda i : (i [0 ], str (i [1 ])) if i else ('other' , _ ('Other' ))
309311 ):
310312 """Query sums of debit and credit for all accounts and domains
311313 used in expressions.
@@ -323,7 +325,7 @@ def do_queries(
323325 domain_by_mode = {}
324326 ends = []
325327 for key in self ._map_account_ids :
326- domain , mode = key
328+ ( domain , mode ) = key
327329 if mode == self .MODE_END and self .smart_end :
328330 # postpone computation of ending balance
329331 ends .append ((domain , mode ))
@@ -336,13 +338,21 @@ def do_queries(
336338 domain .append (("account_id" , "in" , self ._map_account_ids [key ]))
337339 if additional_move_line_filter :
338340 domain .extend (additional_move_line_filter )
341+
342+ get_fields = ["debit" , "credit" , "account_id" , "company_id" ]
343+ group_by_fields = ["account_id" , "company_id" ]
344+ if auto_expand_col_name :
345+ get_fields = [ auto_expand_col_name ] + get_fields
346+ group_by_fields = [ auto_expand_col_name ] + group_by_fields
347+
339348 # fetch sum of debit/credit, grouped by account_id
340349 accs = aml_model .read_group (
341350 domain ,
342- [ "debit" , "credit" , "account_id" , "company_id" ] ,
343- [ "account_id" , "company_id" ] ,
351+ get_fields ,
352+ group_by_fields ,
344353 lazy = False ,
345354 )
355+
346356 for acc in accs :
347357 rate , dp = company_rates [acc ["company_id" ][0 ]]
348358 debit = acc ["debit" ] or 0.0
@@ -352,19 +362,33 @@ def do_queries(
352362 ):
353363 # in initial mode, ignore accounts with 0 balance
354364 continue
355- self ._data [key ][acc ["account_id" ][0 ]] = (debit * rate , credit * rate )
365+ rdi_id = rdi_transformer (acc [auto_expand_col_name ])
366+ if not self ._data [key ].get (rdi_id , False ):
367+ self ._data [key ][rdi_id ] = defaultdict (dict )
368+ self ._data [key ][rdi_id ][acc ["account_id" ][0 ]] = (debit * rate , credit * rate )
356369 # compute ending balances by summing initial and variation
357370 for key in ends :
358371 domain , mode = key
359372 initial_data = self ._data [(domain , self .MODE_INITIAL )]
360373 variation_data = self ._data [(domain , self .MODE_VARIATION )]
361- account_ids = set (initial_data .keys ()) | set (variation_data .keys ())
362- for account_id in account_ids :
363- di , ci = initial_data .get (account_id , (AccountingNone , AccountingNone ))
364- dv , cv = variation_data .get (
365- account_id , (AccountingNone , AccountingNone )
366- )
367- self ._data [key ][account_id ] = (di + dv , ci + cv )
374+ rdis = set (initial_data .keys ()) | set (variation_data .keys ())
375+ for rdi in rdis :
376+ if not initial_data .get (rdi , False ):
377+ initial_data [rdi ] = defaultdict (dict )
378+ if not variation_data .get (rdi , False ):
379+ variation_data [rdi ] = defaultdict (dict )
380+ if not self ._data [key ].get (rdi , False ):
381+ self ._data [key ][rdi ] = defaultdict (dict )
382+ pprint .pprint (rdis )
383+ pprint .pprint (rdi )
384+ pprint .pprint (initial_data )
385+ pprint .pprint (variation_data )
386+
387+ account_ids = set (initial_data [rdi ].keys ()) | set (variation_data [rdi ].keys ())
388+ for account_id in account_ids :
389+ di , ci = initial_data [rdi ].get (account_id , (AccountingNone , AccountingNone ))
390+ dv , cv = variation_data [rdi ].get (account_id , (AccountingNone , AccountingNone ))
391+ self ._data [key ][rdi ][account_id ] = (di + dv , ci + cv )
368392
369393 def replace_expr (self , expr ):
370394 """Replace accounting variables in an expression by their amount.
@@ -377,23 +401,25 @@ def replace_expr(self, expr):
377401 def f (mo ):
378402 field , mode , acc_domain , ml_domain = self ._parse_match_object (mo )
379403 key = (ml_domain , mode )
380- account_ids_data = self ._data [key ]
404+ rdi_ids_data = self ._data [key ]
381405 v = AccountingNone
382406 account_ids = self ._account_ids_by_acc_domain [acc_domain ]
383- for account_id in account_ids :
384- debit , credit = account_ids_data .get (
385- account_id , (AccountingNone , AccountingNone )
386- )
387- if field == "bal" :
388- v += debit - credit
389- elif field == "pbal" and debit >= credit :
390- v += debit - credit
391- elif field == "nbal" and debit < credit :
392- v += debit - credit
393- elif field == "deb" :
394- v += debit
395- elif field == "crd" :
396- v += credit
407+ for rdi in rdi_ids_data :
408+ account_ids_data = self ._data [key ][rdi ]
409+ for account_id in account_ids :
410+ debit , credit = account_ids_data .get (
411+ account_id , (AccountingNone , AccountingNone )
412+ )
413+ if field == "bal" :
414+ v += debit - credit
415+ elif field == "pbal" and debit >= credit :
416+ v += debit - credit
417+ elif field == "nbal" and debit < credit :
418+ v += debit - credit
419+ elif field == "deb" :
420+ v += debit
421+ elif field == "crd" :
422+ v += credit
397423 # in initial balance mode, assume 0 is None
398424 # as it does not make sense to distinguish 0 from "no data"
399425 if (
@@ -424,25 +450,21 @@ def f(mo):
424450 return "(AccountingNone)"
425451 # here we know account_id is involved in acc_domain
426452 account_ids_data = self ._data [key ]
427- debit , credit = account_ids_data .get (
428- account_id , (AccountingNone , AccountingNone )
429- )
430- if field == "bal" :
431- v = debit - credit
432- elif field == "pbal" :
433- if debit >= credit :
434- v = debit - credit
435- else :
436- v = AccountingNone
437- elif field == "nbal" :
438- if debit < credit :
439- v = debit - credit
440- else :
441- v = AccountingNone
442- elif field == "deb" :
443- v = debit
444- elif field == "crd" :
445- v = credit
453+ for rdi in rdi_ids_data :
454+ account_ids_data = self ._data [key ][rdi ]
455+ debit , credit = account_ids_data .get (
456+ account_id , (AccountingNone , AccountingNone )
457+ )
458+ if field == "bal" :
459+ v += debit - credit
460+ elif field == "pbal" and debit >= credit :
461+ v += debit - credit
462+ elif field == "nbal" and debit < credit :
463+ v += debit - credit
464+ elif field == "deb" :
465+ v += debit
466+ elif field == "crd" :
467+ v += credit
446468 # in initial balance mode, assume 0 is None
447469 # as it does not make sense to distinguish 0 from "no data"
448470 if (
@@ -466,6 +488,58 @@ def f(mo):
466488 for account_id in account_ids :
467489 yield account_id , [self ._ACC_RE .sub (f , expr ) for expr in exprs ]
468490
491+ def replace_exprs_by_row_detail (self , exprs ):
492+ """Replace accounting variables in a list of expression
493+ by their amount, iterating by accounts involved in the expression.
494+
495+ yields account_id, replaced_expr
496+
497+ This method must be executed after do_queries().
498+ """
499+
500+ def f (mo ):
501+ field , mode , acc_domain , ml_domain = self ._parse_match_object (mo )
502+ key = (ml_domain , mode )
503+ v = AccountingNone
504+ account_ids_data = self ._data [key ][rdi_id ]
505+ account_ids = self ._account_ids_by_acc_domain [acc_domain ]
506+
507+ for account_id in account_ids :
508+ debit , credit = account_ids_data .get (
509+ account_id , (AccountingNone , AccountingNone )
510+ )
511+ if field == "bal" :
512+ v += debit - credit
513+ elif field == "pbal" and debit >= credit :
514+ v += debit - credit
515+ elif field == "nbal" and debit < credit :
516+ v += debit - credit
517+ elif field == "deb" :
518+ v += debit
519+ elif field == "crd" :
520+ v += credit
521+ # in initial balance mode, assume 0 is None
522+ # as it does not make sense to distinguish 0 from "no data"
523+ if (
524+ v is not AccountingNone
525+ and mode in (self .MODE_INITIAL , self .MODE_UNALLOCATED )
526+ and float_is_zero (v , precision_digits = self .dp )
527+ ):
528+ v = AccountingNone
529+ return "(" + repr (v ) + ")"
530+
531+ rdi_ids = set ()
532+ for expr in exprs :
533+ for mo in self ._ACC_RE .finditer (expr ):
534+ field , mode , acc_domain , ml_domain = self ._parse_match_object (mo )
535+ key = (ml_domain , mode )
536+ rdis_data = self ._data [key ]
537+ for rdi_id in rdis_data .keys ():
538+ rdi_ids .add (rdi_id )
539+
540+ for rdi_id in rdi_ids :
541+ yield rdi_id , [self ._ACC_RE .sub (f , expr ) for expr in exprs ]
542+
469543 @classmethod
470544 def _get_balances (cls , mode , companies , date_from , date_to ):
471545 expr = "deb{mode}[], crd{mode}[]" .format (mode = mode )
0 commit comments