class IfrsLines(models.Model): _name = 'ifrs.lines' _order = 'ifrs_id, sequence' def _get_ifrs_query(self, cr, uid, brw, context=None): """ Fetches a semi-query to be provided as context into aml""" context = dict(context or {}) query = '' if not brw.filter_id: return query args = eval(brw.filter_id.domain) query = self.pool['account.move.line']._where_calc(cr, uid, args, context=context) where_clause, where_clause_params = query.get_sql()[1:] where_clause = where_clause.replace('account_move_line', 'l') query = cr.mogrify(where_clause, where_clause_params) return query def _get_sum_total(self, cr, uid, brw, operand, number_month=None, one_per=False, bag=None, context=None): """ Calculates the sum of the line total_ids & operand_ids the current ifrs.line @param number_month: period to compute """ context = context and dict(context) or {} res = 0 # If the report is two or twelve columns, will choose the field needed # to make the sum if context.get('whole_fy', False) or one_per: field_name = 'ytd' else: field_name = 'period_%s' % str(number_month) # It takes the sum of the total_ids & operand_ids for ttt in getattr(brw, operand): res += bag[ttt.id].get(field_name, 0.0) return res def _get_sum_detail(self, cr, uid, ids=None, number_month=None, context=None): """ Calculates the amount sum of the line type == 'detail' @param number_month: periodo a calcular """ fy_obj = self.pool.get('account.fiscalyear') period_obj = self.pool.get('account.period') context = context and dict(context) or {} cx = context.copy() res = 0.0 if not cx.get('fiscalyear'): cx['fiscalyear'] = fy_obj.find(cr, uid) fy_id = cx['fiscalyear'] brw = self.browse(cr, uid, ids) if brw.acc_val == 'init': if cx.get('whole_fy', False): cx['periods'] = period_obj.search( cr, uid, [('fiscalyear_id', '=', fy_id), ('special', '=', True)]) else: period_from = period_obj.search(cr, uid, [('fiscalyear_id', '=', fy_id), ('special', '=', True)]) # Case when the period_from is the first non-special period # of the fiscalyear if period_obj.browse(cr, uid, cx['period_from']).date_start ==\ fy_obj.browse(cr, uid, fy_id).date_start: cx['period_to'] = period_from[0] else: cx['period_to'] = period_obj.previous( cr, uid, cx['period_from']) cx['period_from'] = period_from[0] elif brw.acc_val == 'var': # it is going to be the one sent by the previous cx if cx.get('whole_fy', False): cx['periods'] = period_obj.search( cr, uid, [('fiscalyear_id', '=', fy_id), ('special', '=', False)]) else: # it is going to be from the fiscalyear's beginning if cx.get('whole_fy', False): cx['periods'] = period_obj.search( cr, uid, [('fiscalyear_id', '=', fy_id)]) else: period_from = period_obj.search(cr, uid, [('fiscalyear_id', '=', fy_id), ('special', '=', True)]) cx['period_from'] = period_from[0] cx['periods'] = \ period_obj.build_ctx_periods(cr, uid, cx['period_from'], cx['period_to']) if brw.type == 'detail': # Si es de tipo detail # If we have to only take into account a set of Journals cx['journal_ids'] = [aj_brw.id for aj_brw in brw.journal_ids] cx['analytic'] = [an.id for an in brw.analytic_ids] cx['ifrs_tax'] = [tx.id for tx in brw.tax_code_ids] cx['ifrs_partner'] = [p_brw.id for p_brw in brw.partner_ids] cx['ifrs_query'] = self._get_ifrs_query(cr, uid, brw, context) # NOTE: This feature is not yet been implemented # cx['partner_detail'] = cx.get('partner_detail') # Refreshing record with new context brw = self.browse(cr, uid, ids, context=cx) for aa in brw.cons_ids: # Se hace la sumatoria de la columna balance, credito o debito. # Dependiendo de lo que se escoja en el wizard if brw.value == 'debit': res += aa.debit elif brw.value == 'credit': res += aa.credit else: res += aa.balance return res def _get_logical_operation(self, cr, uid, brw, ilf, irg, context=None): def result(brw, ifn, ilf, irg): if getattr(brw, ifn) == 'subtract': res = ilf - irg elif getattr(brw, ifn) == 'addition': res = ilf + irg elif getattr(brw, ifn) == 'lf': res = ilf elif getattr(brw, ifn) == 'rg': res = irg elif getattr(brw, ifn) == 'zr': res = 0.0 return res context = dict(context or {}) fnc = getattr(op, brw.logical_operation) if fnc(ilf, irg): res = result(brw, 'logical_true', ilf, irg) else: res = result(brw, 'logical_false', ilf, irg) return res def _get_grand_total(self, cr, uid, ids, number_month=None, one_per=False, bag=None, context=None): """ Calculates the amount sum of the line type == 'total' @param number_month: periodo a calcular """ fy_obj = self.pool.get('account.fiscalyear') context = context and dict(context) or {} cx = context.copy() res = 0.0 if not cx.get('fiscalyear'): cx['fiscalyear'] = fy_obj.find(cr, uid) brw = self.browse(cr, uid, ids) res = self._get_sum_total(cr, uid, brw, 'total_ids', number_month, one_per=one_per, bag=bag, context=cx) if brw.operator in ('subtract', 'condition', 'percent', 'ratio', 'product'): so = self._get_sum_total(cr, uid, brw, 'operand_ids', number_month, one_per=one_per, bag=bag, context=cx) if brw.operator == 'subtract': res -= so elif brw.operator == 'condition': res = self._get_logical_operation(cr, uid, brw, res, so, context=cx) elif brw.operator == 'percent': res = so != 0 and (100 * res / so) or 0.0 elif brw.operator == 'ratio': res = so != 0 and (res / so) or 0.0 elif brw.operator == 'product': res = res * so return res def _get_constant(self, cr, uid, ids=None, number_month=None, context=None): """ Calculates the amount sum of the line of constant @param number_month: periodo a calcular """ cx = context or {} brw = self.browse(cr, uid, ids, context=cx) if brw.constant_type == 'constant': return brw.constant fy_obj = self.pool.get('account.fiscalyear') period_obj = self.pool.get('account.period') if not cx.get('fiscalyear'): cx['fiscalyear'] = fy_obj.find(cr, uid, dt=None, context=cx) if not cx.get('period_from', False) and not cx.get('period_to', False): if context.get('whole_fy', False): cx['period_from'] = period_obj.find_special_period( cr, uid, cx['fiscalyear']) cx['period_to'] = period_obj.search( cr, uid, [('fiscalyear_id', '=', cx['fiscalyear'])])[-1] if brw.constant_type == 'period_days': res = period_obj._get_period_days(cr, uid, cx['period_from'], cx['period_to']) elif brw.constant_type == 'fy_periods': res = fy_obj._get_fy_periods(cr, uid, cx['fiscalyear']) elif brw.constant_type == 'fy_month': res = fy_obj._get_fy_month(cr, uid, cx['fiscalyear'], cx['period_to']) elif brw.constant_type == 'number_customer': res = self._get_number_customer_portfolio(cr, uid, ids, cx['fiscalyear'], cx['period_to'], cx) return res def exchange(self, cr, uid, ids, from_amount, to_currency_id, from_currency_id, exchange_date, context=None): context = context and dict(context) or {} if from_currency_id == to_currency_id: return from_amount curr_obj = self.pool.get('res.currency') context['date'] = exchange_date return curr_obj.compute(cr, uid, from_currency_id, to_currency_id, from_amount, context=context) def _get_amount_value(self, cr, uid, ids, ifrs_line=None, period_info=None, fiscalyear=None, exchange_date=None, currency_wizard=None, number_month=None, target_move=None, pdx=None, undefined=None, two=None, one_per=False, bag=None, context=None): """ Returns the amount corresponding to the period of fiscal year @param ifrs_line: linea a calcular monto @param period_info: informacion de los periodos del fiscal year @param fiscalyear: selected fiscal year @param exchange_date: date of change currency @param currency_wizard: currency in the report @param number_month: period number @param target_move: target move to consider """ context = context and dict(context) or {} # TODO: Current Company's Currency shall be used: the one on wizard from_currency_id = ifrs_line.ifrs_id.company_id.currency_id.id to_currency_id = currency_wizard if number_month: if two: context = { 'period_from': number_month, 'period_to': number_month } else: period_id = period_info[number_month][1] context = {'period_from': period_id, 'period_to': period_id} else: context = {'whole_fy': True} # NOTE: This feature is not yet been implemented # context['partner_detail'] = pdx context['fiscalyear'] = fiscalyear context['state'] = target_move if ifrs_line.type == 'detail': res = self._get_sum_detail(cr, uid, ifrs_line.id, number_month, context=context) elif ifrs_line.type == 'total': res = self._get_grand_total(cr, uid, ifrs_line.id, number_month, one_per=one_per, bag=bag, context=context) elif ifrs_line.type == 'constant': res = self._get_constant(cr, uid, ifrs_line.id, number_month, context=context) else: res = 0.0 if ifrs_line.type == 'detail': res = self.exchange(cr, uid, ids, res, to_currency_id, from_currency_id, exchange_date, context=context) return res def _get_dict_amount_with_operands(self, cr, uid, ids, ifrs_line, period_info=None, fiscalyear=None, exchange_date=None, currency_wizard=None, month_number=None, target_move=None, pdx=None, undefined=None, two=None, one_per=False, bag=None, context=None): """ Integrate operand_ids field in the calculation of the amounts for each line @param ifrs_line: linea a calcular monto @param period_info: informacion de los periodos del fiscal year @param fiscalyear: selected fiscal year @param exchange_date: date of change currency @param currency_wizard: currency in the report @param month_number: period number @param target_move: target move to consider """ context = dict(context or {}) direction = ifrs_line.inv_sign and -1.0 or 1.0 res = {} for number_month in range(1, 13): field_name = 'period_%(month)s' % dict(month=number_month) bag[ifrs_line.id][field_name] = self._get_amount_value( cr, uid, ids, ifrs_line, period_info, fiscalyear, exchange_date, currency_wizard, number_month, target_move, pdx, undefined, two, one_per=one_per, bag=bag, context=context) * direction res[number_month] = bag[ifrs_line.id][field_name] return res def _get_amount_with_operands(self, cr, uid, ids, ifrs_l, period_info=None, fiscalyear=None, exchange_date=None, currency_wizard=None, number_month=None, target_move=None, pdx=None, undefined=None, two=None, one_per=False, bag=None, context=None): """ Integrate operand_ids field in the calculation of the amounts for each line @param ifrs_line: linea a calcular monto @param period_info: informacion de los periodos del fiscal year @param fiscalyear: selected fiscal year @param exchange_date: date of change currency @param currency_wizard: currency in the report @param number_month: period number @param target_move: target move to consider """ context = context and dict(context) or {} if not number_month: context = {'whole_fy': True} res = self._get_amount_value(cr, uid, ids, ifrs_l, period_info, fiscalyear, exchange_date, currency_wizard, number_month, target_move, pdx, undefined, two, one_per=one_per, bag=bag, context=context) res = ifrs_l.inv_sign and (-1.0 * res) or res bag[ifrs_l.id]['ytd'] = res return res def _get_number_customer_portfolio(self, cr, uid, ids, fyr, period, context=None): ifrs_brw = self.browse(cr, uid, ids, context=context) company_id = ifrs_brw.ifrs_id.company_id.id if context.get('whole_fy', False): period_fy = [('period_id.fiscalyear_id', '=', fyr), ('period_id.special', '=', False)] else: period_fy = [('period_id', '=', period)] invoice_obj = self.pool.get('account.invoice') invoice_ids = invoice_obj.search( cr, uid, [('type', '=', 'out_invoice'), ('state', 'in', ( 'open', 'paid', )), ('company_id', '=', company_id)] + period_fy) partner_number = \ set([inv.partner_id.id for inv in invoice_obj.browse(cr, uid, invoice_ids, context=context)]) return len(list(partner_number)) def onchange_sequence(self, cr, uid, ids, sequence, context=None): context = context and dict(context) or {} return {'value': {'priority': sequence}} @api.returns('self') def _get_default_help_bool(self): ctx = dict(self._context) return ctx.get('ifrs_help', True) @api.returns('self') def _get_default_sequence(self): ctx = dict(self._context) res = 0 if not ctx.get('ifrs_id'): return res + 10 ifrs_lines_ids = self.search([('ifrs_id', '=', ctx['ifrs_id'])]) if ifrs_lines_ids: res = max(line.sequence for line in ifrs_lines_ids) return res + 10 def onchange_type_without(self, cr, uid, ids, ttype, operator, context=None): context = context and dict(context) or {} res = {} if ttype == 'total' and operator == 'without': res = {'value': {'operand_ids': []}} return res def write(self, cr, uid, ids, vals, context=None): ids = isinstance(ids, (int, long)) and [ids] or ids res = super(IfrsLines, self).write(cr, uid, ids, vals) for ifrs_line in self.pool.get('ifrs.lines').browse(cr, uid, ids): if ifrs_line.type == 'total' and ifrs_line.operator == 'without': vals['operand_ids'] = [(6, 0, [])] super(IfrsLines, self).write(cr, uid, ifrs_line.id, vals) return res help = fields.Boolean(string='Show Help', copy=False, related='ifrs_id.help', default=_get_default_help_bool, help='Allows you to show the help in the form') # Really!!! A repeated field with same functionality! This was done due # to the fact that web view everytime that sees sequence tries to allow # you to change the values and this feature here is undesirable. sequence = fields.Integer( string='Sequence', default=_get_default_sequence, help=('Indicates the order of the line in the report. The sequence ' 'must be unique and unrepeatable')) priority = fields.Integer( string='Sequence', default=_get_default_sequence, related='sequence', help=('Indicates the order of the line in the report. The sequence ' 'must be unique and unrepeatable')) name = fields.Char( string='Name', size=128, required=True, translate=True, help=('Line name in the report. This name can be translatable, if ' 'there are multiple languages loaded it can be translated')) type = fields.Selection( [('abstract', 'Abstract'), ('detail', 'Detail'), ('constant', 'Constant'), ('total', 'Total')], string='Type', required=True, default='abstract', help=('Line type of report: \n-Abstract(A),\n-Detail(D), ' '\n-Constant(C),\n-Total(T)')) constant = fields.Float( string='Constant', help=('Fill this field with your own constant that will be used ' 'to compute in your other lines'), readonly=False) constant_type = fields.Selection( [('constant', 'My Own Constant'), ('period_days', 'Days of Period'), ('fy_periods', "FY's Periods"), ('fy_month', "FY's Month"), ('number_customer', "Number of customers* in portfolio")], string='Constant Type', required=False, help='Constant Type') ifrs_id = fields.Many2one('ifrs.ifrs', string='IFRS', required=True) company_id = fields.Many2one('res.company', string='Company', related='ifrs_id.company_id', store=True) amount = fields.Float( string='Amount', readonly=True, help=('This field will update when you click the compute button in ' 'the IFRS doc form')) cons_ids = fields.Many2many('account.account', 'ifrs_account_rel', 'ifrs_lines_id', 'account_id', string='Consolidated Accounts') journal_ids = fields.Many2many('account.journal', 'ifrs_journal_rel', 'ifrs_lines_id', 'journal_id', string='Journals', required=False) analytic_ids = fields.Many2many('account.analytic.account', 'ifrs_analytic_rel', 'ifrs_lines_id', 'analytic_id', string='Consolidated Analytic Accounts') partner_ids = fields.Many2many('res.partner', 'ifrs_partner_rel', 'ifrs_lines_id', 'partner_id', string='Partners') tax_code_ids = fields.Many2many('account.tax.code', 'ifrs_tax_rel', 'ifrs_lines_id', 'tax_code_id', string='Tax Codes') filter_id = fields.Many2one( 'ir.filters', string='Custom Filter', ondelete='set null', domain=("[('model_id','=','account.move.line')]")) parent_id = fields.Many2one( 'ifrs.lines', string='Parent', ondelete='set null', domain=("[('ifrs_id','=',parent.id)," "('type','=','total'),('id','!=',id)]")) operand_ids = fields.Many2many('ifrs.lines', 'ifrs_operand_rel', 'ifrs_parent_id', 'ifrs_child_id', string='Second Operand') operator = fields.Selection( [('subtract', 'Subtraction'), ('condition', 'Conditional'), ('percent', 'Percentage'), ('ratio', 'Ratio'), ('product', 'Product'), ('without', 'First Operand Only')], string='Operator', required=False, default='without', help='Leaving blank will not take into account Operands') logical_operation = fields.Selection( LOGICAL_OPERATIONS, string='Logical Operations', required=False, help=('Select type of Logical Operation to perform with First ' '(Left) and Second (Right) Operand')) logical_true = fields.Selection( LOGICAL_RESULT, string='Logical True', required=False, help=('Value to return in case Comparison is True')) logical_false = fields.Selection( LOGICAL_RESULT, string='Logical False', required=False, help=('Value to return in case Comparison is False')) comparison = fields.Selection( [('subtract', 'Subtraction'), ('percent', 'Percentage'), ('ratio', 'Ratio'), ('without', 'No Comparison')], string='Make Comparison', required=False, default='without', help=('Make a Comparison against the previous period.\nThat is, ' 'period X(n) minus period X(n-1)\nLeaving blank will not ' 'make any effects')) acc_val = fields.Selection([('init', 'Initial Values'), ('var', 'Variation in Periods'), ('fy', ('Ending Values'))], string='Accounting Span', required=False, default='fy', help='Leaving blank means YTD') value = fields.Selection([('debit', 'Debit'), ('credit', 'Credit'), ('balance', 'Balance')], string='Accounting Value', required=False, default='balance', help='Leaving blank means Balance') total_ids = fields.Many2many('ifrs.lines', 'ifrs_lines_rel', 'parent_id', 'child_id', string='First Operand') inv_sign = fields.Boolean(string='Change Sign to Amount', default=False, copy=True, help='Allows you to show the help in the form') invisible = fields.Boolean( string='Invisible', default=False, copy=True, help='Allows whether the line of the report is printed or not') comment = fields.Text(string='Comments/Question', help='Comments or questions about this ifrs line') _sql_constraints = [ ('sequence_ifrs_id_unique', 'unique(sequence, ifrs_id)', 'The sequence already have been set in another IFRS line') ] def _get_level(self, cr, uid, lll, tree, level=1, context=None): """ Calcula los niveles de los ifrs.lines, tomando en cuenta que sera un mismo arbol para los campos total_ids y operand_ids. @param lll: objeto a un ifrs.lines @param level: Nivel actual de la recursion @param tree: Arbol de dependencias entre lineas construyendose """ context = context and dict(context) or {} if not tree.get(level): tree[level] = {} # The search through level should be backwards from the deepest level # to the outmost level levels = tree.keys() levels.sort() levels.reverse() xlevel = False for nnn in levels: xlevel = isinstance(tree[nnn].get(lll.id), (set)) and nnn or xlevel if not xlevel: tree[level][lll.id] = set() elif xlevel < level: tree[level][lll.id] = tree[xlevel][lll.id] del tree[xlevel][lll.id] else: # xlevel >= level return True for jjj in set(lll.total_ids + lll.operand_ids): tree[level][lll.id].add(jjj.id) self._get_level(cr, uid, jjj, tree, level + 1, context=context) return True
class Reportscraped(models.TransientModel): _name = 'report.scraped' product_product = fields.Many2many('product.product', string='Product') partner_id = fields.Many2one('res.partner', 'Customer') sale_order = fields.Many2one('sale.order', 'Sale order') start_date = fields.Date('From') end_date = fields.Date('To') def _get_res_from_sql(self): user_id = self._context['uid'] select_statement = """ select s.id as sale_id, s.partner_id as customer_id, p.id as product_name, rr.name as process_name, sum(r.finished_qty) as finished_qty, sum(r.scraped_qty) as scraped_qty, rr.code as process_code """ from_statement = """ from mrp_production mo join mrp_production_workcenter_line wol on mo.id = wol.production_id left join mrp_workcenter_line_reporting r on wol.id = r.workcenter_line_id join product_product p on mo.product_id = p.id join res_users u on u.id = %s join mrp_workcenter mw on mw.id = wol.workcenter_id join resource_resource rr on mw.resource_id = rr.id left join sale_order s on position( s.name || ':' in mo.origin) > 0 """ % user_id where_statement = 'where mo.company_id = u.company_id' if self.start_date and self.end_date: where_statement = """ where wol.date_start >= cast('%s' as date) and wol.date_start <= cast('%s' as date) and mo.company_id = u.company_id """ % (self.start_date, self.end_date) elif self.start_date and not self.end_date: where_statement = """ where wol.date_start >= cast('%s' as date) and mo.company_id = u.company_id """ % self.start_date elif not self.start_date and self.end_date: where_statement = """ where wol.date_start <= cast('%s' as date) and mo.company_id = u.company_id """ % self.end_date group_statement = """ group by s.id, s.partner_id, p.id, rr.name, rr.code """ order_statement = """ order by sale_id, product_name, process_code, process_name """ psql_statement = """ select sale_id, customer_id, product_name, process_name, scraped_qty, finished_qty, process_code from (%s %s %s %s) as l where finished_qty + scraped_qty > 0 %s; """ % (select_statement, from_statement, where_statement, group_statement, order_statement) self._cr.execute(psql_statement) return self._cr.fetchall() def _get_workcenters_name(self): workcenters = sorted(self.env['mrp.workcenter'].search([]), key=lambda rec: rec['code']) return [workcenter.name for workcenter in workcenters] def _is_product_id_not_in_ids(self, id): if self.product_product: for product in self.product_product: if product.id == id: return False return True return False def _get_product_attributes(self, res, ids): if not res: return {} products = self.env['product.product'].search([('id', 'in', ids)]) vals = {} for product in products: vals[product.id] = { 'bottom': "", 'inside': "", 'outside': "", } for attribue_line_id in product.attribute_line_ids: if attribue_line_id.attribute_id: if attribue_line_id.value_ids: if attribue_line_id.attribute_id.name == u'Bottom': vals[product.id]['bottom'] = \ attribue_line_id.value_ids.name if attribue_line_id.attribute_id.name == u'\ Inner coating': vals[product.id]['inside'] = \ attribue_line_id.value_ids.name if attribue_line_id.attribute_id.name == u'\ Exterior coating': vals[product.id]['outside'] = \ attribue_line_id.value_ids.name return vals def _get_lines_write_excel(self): res = self._get_res_from_sql() product_ids = list(set([line[2] for line in res])) attributes = self._get_product_attributes(res, product_ids) vals = {} for record in res: name = record[0] or False customer = record[1] or False product = record[2] process = record[3] scraped_qty = record[4] or 0 finished_qty = record[5] or 0 if self.sale_order and self.sale_order.id != name: continue if self.partner_id and self.partner_id.id != customer: continue if self._is_product_id_not_in_ids(product): continue if name: name = self.env['sale.order'].browse(name).name else: name = "" if customer: customer = self.env['res.partner'].browse(customer).name else: customer = "" product_name = self.env['product.product'].browse(product).name key = str(product) + ":" + name if key in vals.keys(): if process in vals[key]['process']: vals[key]['quantity'] += finished_qty vals[key]['scraped_qty'][process] += scraped_qty vals[key]['total_scraped'] += scraped_qty pencertage = round( vals[key]['total_scraped'] / (vals[key]['quantity'] + vals[key]['\ total_scraped']) * 100, 2) vals[key]['scraped_percentage'] = pencertage else: vals[key]['quantity'] = finished_qty vals[key]['process'].append(process) vals[key]['scraped_qty'][process] = scraped_qty vals[key]['total_scraped'] += scraped_qty pencertage = round( vals[key]['total_scraped'] / (finished_qty + vals[key]['total_scraped']) * 100, 2) vals[key]['scraped_percentage'] = pencertage else: pencertage = round( scraped_qty / (scraped_qty + finished_qty) * 100, 2) vals[key] = { 'name': name, 'customer': customer, 'product': product_name, 'quantity': finished_qty, 'process': [process], 'scraped_qty': { process: scraped_qty }, 'total_scraped': scraped_qty, 'scraped_percentage': pencertage } vals[key]['bottom'] = attributes[product]['bottom'] vals[key]['inside'] = attributes[product]['inside'] vals[key]['outside'] = attributes[product]['outside'] return vals def _get_process_len(self, vals): length = 0 for key, val in vals.items(): if len(val['process']) > length: length = len(val['process']) return length def _get_table_titile(self, process_len): # save the format in col:title title = { u'0': u"Sales Order", u'1': u"Customer", u'2': u"Products", u'3': u"Bottom", u'4': u"Inner coating", u'5': u"Exterior coating", u'6': u"Quantity completion", u'7': u"Total scrap amount", u'8': u"Scrappage", } index = 9 for name in self._get_workcenters_name(): title[index] = name index = index + 1 return title @api.multi def print_report(self): vals = self._get_lines_write_excel() process_len = self._get_process_len(vals) title = self._get_table_titile(process_len) datas = {'model': 'report.scraped', 'title': title, 'records': vals} return { 'type': 'ir.actions.report.xml', 'report_name': 'mrp.scraped.xls', 'datas': datas }
class Session(models.Model): _name = 'openacademy.session' name = fields.Char(required=True) start_date = fields.Date(default=fields.Date.today) duration = fields.Float(digit=(6, 2), help="Duration in days") seats = fields.Integer(string="Number of Seats") active = fields.Boolean(default=True) color = fields.Integer() instructor_id = fields.Many2one('res.partner', string='Instructor', domain=[ '|', ('instructor', '=', True), ('category_id.name', 'ilike', "Teacher") ]) course_id = fields.Many2one('openacademy.course', ondelte='cascade', string='Course', required=True) attendee_ids = fields.Many2many('res.partner', string="Attendees") taken_seats = fields.Integer(string='Taken seats', compute='_taken_seats') end_date = fields.Date(string="End Date", store=True, compute='_get_end_date', inverse='_set_end_date') hours = fields.Float(string="Duration in hours", compute='_get_hours', inverse='_set_hours') attendees_count = fields.Integer(string="Attendee count", compute="_get_attendees_count", store=True) state = fields.Selection([ ('draft', "Draft"), ('confirmed', "Confirmed"), ('done', "Done"), ]) @api.one def action_draft(self): self.state = 'draft' @api.one def action_confirm(self): self.state = 'confirmed' @api.one def action_done(self): self.state = 'done' @api.one @api.depends('seats', 'attendee_ids') def _taken_seats(self): if not self.seats: self.taken_seats = 0.0 else: self.taken_seats = 100.0 * len(self.attendee_ids) / self.seats @api.onchange('seats', 'attendee_ids') def _verify_valid_seats(self): if self.seats < 0: return { 'warning': { 'title': _("Incorrect 'seats' value"), 'message': _("The number of available seats may not be negative"), }, } if self.seats < len(self.attendee_ids): return { 'warning': { 'title': _("Too many attendees"), 'message': _("Increase seats or remove excess attendees"), }, } @api.one @api.depends('start_date', 'duration') def _get_end_date(self): if not (self.start_date and self.duration): self.end_date = self.start_date return # Add duration to start_date, but: Monday + 5 days = Saturday, so # subtract one second to get on Friday instead start = fields.Datetime.from_string(self.start_date) duration = timedelta(days=self.duration, seconds=-1) self.end_date = start + duration @api.one def _set_end_date(self): if not (self.start_date and self.end_date): return # Compute the difference between dates, but: Friday - Monday = 4 days, # so add one day to get 5 days instead start_date = fields.Datetime.from_string(self.start_date) end_date = fields.Datetime.from_string(self.end_date) self.duration = (end_date - start_date).days + 1 @api.one @api.depends('duration') def _get_hours(self): self.hours = self.duration * 24 @api.one def _set_hours(self): self.duration = self.hours / 24 @api.one @api.depends('attendee_ids') def _get_attendees_count(self): self.attendees_count = len(self.attendee_ids) @api.one @api.constrains('instructor_id', 'attendee_ids') def _check_instructor_not_in_attendees(self): if self.instructor_id and (self.instructor_id in self.attendee_ids): raise exceptions.ValidationError( _("A session's instructor can't be an attendee"))
class L10nEsAeatMod347PartnerRecord(models.Model): _name = 'l10n.es.aeat.mod347.partner_record' _description = 'Partner Record' _rec_name = "partner_vat" @api.model def _default_record_id(self): return self.env.context.get('report_id', False) report_id = fields.Many2one( comodel_name='l10n.es.aeat.mod347.report', string='AEAT 347 Report', ondelete="cascade", default=_default_record_id, ) operation_key = fields.Selection( selection=[ ('A', u'A - Adquisiciones de bienes y servicios superiores al ' u'límite (1)'), ('B', u'B - Entregas de bienes y servicios superiores al límite (1)'), ('C', u'C - Cobros por cuenta de terceros superiores al límite (3)'), ('D', u'D - Adquisiciones efectuadas por Entidades Públicas ' u'(...) superiores al límite (1)'), ('E', u'E - Subvenciones, auxilios y ayudas satisfechas por Ad. ' u'Públicas superiores al límite (1)'), ('F', u'F - Ventas agencia viaje'), ('G', u'G - Compras agencia viaje'), ], string='Operation Key', ) partner_id = fields.Many2one(comodel_name='res.partner', string='Partner', required=True) partner_vat = fields.Char(string='VAT number', size=9) representative_vat = fields.Char(string='L.R. VAT number', size=9, help="Legal Representative VAT number") community_vat = fields.Char( string='Community vat number', size=17, help="VAT number for professionals established in other state " "member without national VAT") partner_country_code = fields.Char(string='Country Code', size=2) partner_state_code = fields.Char(string='State Code', size=2) first_quarter = fields.Float( string="First quarter operations", digits=dp.get_precision('Account'), help="Total amount of first quarter in, out and refund invoices " "for this partner", readonly=True, ) first_quarter_real_estate_transmission_amount = fields.Float( string="First quarter real estate", digits=dp.get_precision('Account'), help="Total amount of first quarter real estate transmissions " "for this partner", ) first_quarter_cash_amount = fields.Float( string="First quarter cash movements", readonly=True, digits=dp.get_precision('Account'), help="Total amount of first quarter cash movements for this partner", ) second_quarter = fields.Float( string="Second quarter operations", digits=dp.get_precision('Account'), help="Total amount of second quarter in, out and refund invoices " "for this partner", readonly=True, ) second_quarter_real_estate_transmission_amount = fields.Float( string="Second quarter real estate", digits=dp.get_precision('Account'), help="Total amount of second quarter real estate transmissions " "for this partner", ) second_quarter_cash_amount = fields.Float( string="Second quarter cash movements", readonly=True, digits=dp.get_precision('Account'), help="Total amount of second quarter cash movements for this partner", ) third_quarter = fields.Float( string="Third quarter operations", digits=dp.get_precision('Account'), help="Total amount of third quarter in, out and refund invoices " "for this partner", readonly=True, ) third_quarter_real_estate_transmission_amount = fields.Float( string="Third quarter real estate", digits=dp.get_precision('Account'), help="Total amount of third quarter real estate transmissions " "for this partner", ) third_quarter_cash_amount = fields.Float( string="Third quarter cash movements", readonly=True, digits=dp.get_precision('Account'), help="Total amount of third quarter cash movements for this partner", ) fourth_quarter = fields.Float( string="Fourth quarter operations", digits=dp.get_precision('Account'), help="Total amount of fourth quarter in, out and refund invoices " "for this partner", readonly=True, ) fourth_quarter_real_estate_transmission_amount = fields.Float( string="Fourth quarter real estate", digits=dp.get_precision('Account'), help="Total amount of fourth quarter real estate transmissions " "for this partner") fourth_quarter_cash_amount = fields.Float( string="Fourth quarter cash movements", readonly=True, digits=dp.get_precision('Account'), help="Total amount of fourth quarter cash movements for this partner", ) amount = fields.Float(string='Operations amount', digits=(13, 2)) cash_amount = fields.Float(string='Received cash amount', digits=(13, 2)) real_estate_transmissions_amount = fields.Float( string='Real Estate Transmisions amount', digits=(13, 2), ) insurance_operation = fields.Boolean( string='Insurance Operation', help="Only for insurance companies. Set to identify insurance " "operations aside from the rest.", ) cash_basis_operation = fields.Boolean( string='Cash Basis Operation', help="Only for cash basis operations. Set to identify cash basis " "operations aside from the rest.", ) tax_person_operation = fields.Boolean( string='Taxable Person Operation', help="Only for taxable person operations. Set to identify taxable " "person operations aside from the rest.", ) related_goods_operation = fields.Boolean( string='Related Goods Operation', help="Only for related goods operations. Set to identify related " "goods operations aside from the rest.", ) bussiness_real_estate_rent = fields.Boolean( string='Bussiness Real Estate Rent', help="Set to identify real estate rent operations aside from the rest." " You'll need to fill in the real estate info only when you are " "the one that receives the money.", ) origin_year = fields.Integer( string='Origin year', help="Origin cash operation year", ) invoice_record_ids = fields.One2many( comodel_name='l10n.es.aeat.mod347.invoice_record', inverse_name='partner_record_id', string='Invoice records', ) real_estate_record_ids = fields.Many2many( compute="_compute_real_estate_record_ids", comodel_name="l10n.es.aeat.mod347.real_estate_record", string='Real Estate Records', ) cash_record_ids = fields.One2many( comodel_name='l10n.es.aeat.mod347.cash_record', inverse_name='partner_record_id', string='Payment records', ) check_ok = fields.Boolean( compute="_compute_check_ok", string='Record is OK', store=True, readonly=True, help='Checked if this record is OK', ) @api.multi def _compute_real_estate_record_ids(self): """Get the real estate records from this record parent report for this partner. """ self.real_estate_record_ids = self.env[ 'l10n.es.aeat.mod347.real_estate_record'] if self.partner_id: self.real_estate_record_ids = self.real_estate_record_ids.search([ ('report_id', '=', self.report_id.id), ('partner_id', '=', self.partner_id.id) ]) @api.multi @api.depends('partner_country_code', 'partner_state_code', 'partner_vat', 'community_vat') def _compute_check_ok(self): for record in self: record.check_ok = (record.partner_country_code and record.partner_state_code and record.partner_state_code.isdigit() and (record.partner_vat or record.partner_country_code != 'ES')) @api.onchange('partner_id') def onchange_partner_id(self): """Loads some partner data (country, state and vat) when the selected partner changes. """ if self.partner_id: addr = self.partner_id.address_get(['delivery', 'invoice']) # Get the invoice or the default address of the partner addr = self.partner_id.address_get(['invoice', 'default']) address = self.env['res.partner'].browse(addr['invoice']) self.partner_vat = self.partner_id.vat and \ re.match("(ES){0,1}(.*)", self.partner_id.vat).groups()[1] self.partner_state_code = address.state_id.code self.partner_country_code = address.country_id.code else: self.partner_vat = '' self.partner_country_code = '' self.partner_state_code = '' @api.multi @api.depends('invoice_record_ids.invoice_id.date', 'report_id.year') def calculate_quarter_totals(self): def calc_amount_by_quarter(invoices, refunds, year, month_start): day_start = 1 month_end = month_start + 2 day_end = monthrange(year, month_end)[1] date_start = fields.Date.to_string( datetime(year, month_start, day_start)) date_end = fields.Date.to_string(datetime(year, month_end, day_end)) return (sum( invoices.filtered(lambda x: date_start <= x.invoice_id.date <= date_end).mapped('amount')) - sum( refunds.filtered(lambda x: date_start <= x.invoice_id. date <= date_end).mapped('amount'))) for record in self: year = record.report_id.year invoices = record.invoice_record_ids.filtered(lambda rec: ( rec.invoice_id.type in ('out_invoice', 'in_invoice'))) refunds = record.invoice_record_ids.filtered(lambda rec: ( rec.invoice_id.type in ('out_refund', 'in_refund'))) record.first_quarter = calc_amount_by_quarter( invoices, refunds, year, 1, ) record.second_quarter = calc_amount_by_quarter( invoices, refunds, year, 4, ) record.third_quarter = calc_amount_by_quarter( invoices, refunds, year, 7, ) record.fourth_quarter = calc_amount_by_quarter( invoices, refunds, year, 10, ) @api.multi def calculate_quarter_cash_totals(self): def calc_amount_by_quarter(records, year, month_start): day_start = 1 month_end = month_start + 2 day_end = monthrange(year, month_end)[1] date_start = fields.Date.to_string( datetime(year, month_start, day_start)) date_end = fields.Date.to_string(datetime(year, month_end, day_end)) return sum( records.filtered(lambda x: date_start <= x.invoice_id.date <= date_end).mapped('amount')) for record in self: if not record.cash_record_ids: continue year = record.report_id.year record.first_quarter_cash_amount = calc_amount_by_quarter( record.cash_record_ids, year, 1, ) record.second_quarter_cash_amount = calc_amount_by_quarter( record.cash_record_ids, year, 4, ) record.third_quarter_cash_amount = calc_amount_by_quarter( record.cash_record_ids, year, 7, ) record.fourth_quarter_cash_amount = calc_amount_by_quarter( record.cash_record_ids, year, 10, ) # Totals record.cash_amount = sum([ record.first_quarter_cash_amount, record.second_quarter_cash_amount, record.third_quarter_cash_amount, record.fourth_quarter_cash_amount ])
class JasperReportReceivableConfirmationLetter(models.TransientModel): _name = 'receivable.confirmation.letter' _inherit = 'report.account.common' fiscalyear_start_id = fields.Many2one(default=False, ) fiscalyear_end_id = fields.Many2one(default=False, ) filter = fields.Selection( readonly=True, default='filter_date', ) date_report = fields.Date( string='Report Date', required=True, default=lambda self: fields.Date.context_today(self), ) account_ids = fields.Many2many( 'account.account', string='Accounts', domain=[('type', '=', 'receivable')], ) partner_ids = fields.Many2many( 'res.partner', string='Customers', domain=[('customer', '=', True)], ) @api.multi def _get_report_name(self): self.ensure_one() report_name = "receivable_confirmation_letter" return report_name @api.multi def _get_sql_condition(self): self.ensure_one() condition = "a.type = 'receivable'" if self.account_ids: if len(self.account_ids) > 1: condition += \ " AND a.id IN %s" % (str(tuple(self.account_ids.ids)), ) else: condition += "AND a.id = %s" % (self.account_ids.id, ) if self.partner_ids: if len(self.partner_ids) > 1: condition += " AND l.partner_id IN %s" \ % (str(tuple(self.partner_ids.ids)), ) else: condition += " AND l.partner_id = %s" % (self.partner_ids.id, ) # Check for History View condition += " AND l.date_created <= '%s' \ AND (l.reconcile_id IS NULL OR \ l.date_reconciled > '%s')" \ % (self.date_report, self.date_report, ) return condition @api.multi def _get_move_line_ids(self): self.ensure_one() self._cr.execute(""" SELECT l.id FROM account_move_line l LEFT JOIN account_account a ON l.account_id = a.id WHERE %s""" % (self._get_sql_condition(), )) move_line_ids = list(map(lambda l: l[0], self._cr.fetchall())) # If not found data if not move_line_ids: raise ValidationError(_('No Data!')) return move_line_ids @api.multi def _get_datas(self): self.ensure_one() data = {'parameters': {}} data['parameters']['ids'] = self._get_move_line_ids() date_report = datetime.strptime(self.date_report, '%Y-%m-%d') data['parameters']['date_report'] = date_report.strftime('%d/%m/%Y') data['parameters']['date_run'] = time.strftime('%d/%m/%Y') data['parameters']['company_name'] = \ self.company_id.partner_id.with_context(lang="th_TH").name return data @api.multi def run_report(self): self.ensure_one() return { 'type': 'ir.actions.report.xml', 'report_name': self._get_report_name(), 'datas': self._get_datas(), }
class add_hours_wizard(models.TransientModel): _name = "add_hours.wizard" def _default_partner(self): # pdb.set_trace() return self.env['account.invoice'].browse( self.env['account.invoice']._context.get('active_id')).partner_id def _default_hours_ids(self): search_domain = [('account_id.partner_id', '=', self.env['account.invoice'].browse( self._context.get('active_id')).partner_id.id)] search_domain = search_domain + [('invoice_id', '=', False)] search_domain = search_domain + [('to_invoice', '!=', False)] return self.env['account.analytic.line'].search(search_domain) def _default_invoice(self): #pdb.set_trace() return self.env['account.invoice'].browse( self.env['account.invoice']._context.get('active_id')) def _default_product(self): #pdb.set_trace() return self.env['account.invoice'].browse( self.env['account.invoice']._context.get( 'active_id')).company_id.default_hours_product partner_id = fields.Many2one('res.partner', string="Customer", readonly=True, default=_default_partner) product_id = fields.Many2one('product.product', string="Product", required=True, default=_default_product) invoice_id = fields.Many2one('account.invoice', readonly=True, string="Invoice", default=_default_invoice) hours_ids = fields.Many2many("account.analytic.line", default=_default_hours_ids) @api.multi def add_hours_to_invoice(self): # obj_invoice_lines=self.invoice_id.create({'product_id':self.product_id}) total = 0 for l in self.hours_ids: l._calculate_invoicable() total = total + l.amount_total obj_invoice_lines = self.env['account.invoice.line'] # pdb.set_trace() invoice_line = { ('price_unit', total), ('invoice_id', self.invoice_id.id), ('name', self.product_id.name), ('product_id', self.product_id.id), ('uos_id', self.product_id.uom_id.id), ('account_analytic_id', l.account_id.id), ('account_id', self.product_id.property_account_income.id | self.product_id.categ_id.property_account_income_categ.id), #('invoice_line_tax_id',[(6, 0, self.product_id.taxes_id)]), } #pdb.set_trace() obj_invoice_lines = obj_invoice_lines.create(invoice_line) obj_invoice_lines.invoice_line_tax_id = self.env[ 'account.fiscal.position'].browse( self.invoice_id.fiscal_position.id).map_tax( self.product_id.taxes_id) for l in self.hours_ids: l.write({'invoice_id': self.invoice_id.id}) # self.write([l.id for l in self.hours_ids], {'invoice_id': self.invoice_id.id}) self.env['account.invoice'].browse( self.invoice_id.id).button_reset_taxes()
class XLSXReportAsset(models.TransientModel): _name = 'xlsx.report.asset' _inherit = 'report.account.common' filter = fields.Selection( [('filter_date', 'Dates'), ('filter_period', 'Periods')], string='Filter by', required=True, default='filter_period', ) asset_status_draft = fields.Boolean( string='Draft', ) asset_status_open = fields.Boolean( string='Running', ) asset_status_close = fields.Boolean( string='Close', ) asset_status_removed = fields.Boolean( string='Removed', ) asset_status = fields.Selection( [('draft', 'Draft'), ('open', 'Running'), ('close', 'Close'), ('removed', 'Removed')], string=' Asset Status' ) asset_ids = fields.Many2many( 'account.asset', string='Asset Code', ) asset_profile_ids = fields.Many2many( 'account.asset.profile', string='Asset Profile', ) date_filter = fields.Char( compute='_compute_date_filter', string='Date Filter', ) # Note: report setting accum_depre_account_type = fields.Many2one( 'account.account.type', string='Account Type for Accum.Depre.', required=True, help="Define account type for accumulated depreciation account, " "to be used in report query SQL." ) depre_account_type = fields.Many2one( 'account.account.type', string='Account Type for Depre.', required=True, help="Define account type for depreciation account, " "to be used in report query SQL." ) results = fields.Many2many( 'asset.view', string='Results', compute='_compute_results', help='Use compute fields, so there is nothing store in database', ) @api.model def _domain_to_where_str(self, domain): """ Helper Function for better performance """ where_dom = [" %s %s %s " % (x[0], x[1], isinstance(x[2], basestring) and "'%s'" % x[2] or x[2]) for x in domain] where_str = 'and'.join(where_dom) return where_str @api.multi def _compute_results(self): self.ensure_one() dom = [] status = [] # Prepare DOM to filter assets if self.asset_status_draft: status += ['draft'] if self.asset_status_open: status += ['open'] if self.asset_status_close: status += ['close'] if self.asset_status_removed: status += ['removed'] if self.asset_ids: dom += [('id', 'in', tuple(self.asset_ids.ids + [0]))] if self.asset_profile_ids: dom += [('profile_id', 'in', tuple(self.asset_profile_ids.ids + [0]))] if status: dom += [('state', 'in', tuple(status + ['']))] # Prepare fixed params date_start = False date_end = False # fiscalyear_start = self.fiscalyear_start_id.name if self.filter == 'filter_date': date_start = self.date_start date_end = self.date_end if self.filter == 'filter_period': date_start = self.period_start_id.date_start date_end = self.period_end_id.date_stop if not date_start or not date_end: raise ValidationError(_('Please provide from and to dates.')) accum_depre_account_ids = self.env['account.account'].search( [('user_type', '=', self.accum_depre_account_type.id)]).ids depre_account_ids = self.env['account.account'].search( [('user_type', '=', self.depre_account_type.id)]).ids where_str = self._domain_to_where_str(dom) if where_str: where_str = 'and ' + where_str self._cr.execute(""" select a.*, id asset_id, -- depreciation (select coalesce(sum(debit-credit), 0.0) from account_move_line ml where account_id in %s -- depreciation account and ml.date between %s and %s and asset_id = a.id) depreciation, -- accumulated_cf (select coalesce(sum(credit-debit), 0.0) from account_move_line ml where account_id in %s -- accumulated account and ml.date <= %s -- date end and asset_id = a.id) accumulated_cf, -- accumulated_bf case when a.date_start >= %s then 0 else (select a.purchase_value - coalesce(sum(credit-debit), 0.0) from account_move_line ml join account_period ap on ap.id = ml.period_id join account_fiscalyear af on af.id = ap.fiscalyear_id where account_id in %s -- accumulatedp account and ml.date < %s and asset_id = a.id) end accumulated_bf from account_asset a where (a.state != 'close' or a.value_depreciated != 0) """ + where_str + "order by profile_id, number", (tuple(depre_account_ids), date_start, date_end, tuple(accum_depre_account_ids), date_end, date_start, tuple(accum_depre_account_ids), date_start)) asset_results = self._cr.dictfetchall() ReportLine = self.env['asset.view'] for line in asset_results: self.results += ReportLine.new(line) @api.multi def _compute_date_filter(self): if self.filter == 'filter_date': date_start = self.date_start date_end = self.date_end elif self.filter == 'filter_period': date_start = self.period_start_id.date_start date_end = self.period_end_id.date_stop else: date_start = self.fiscalyear_start_id.date_start date_end = self.fiscalyear_end_id.date_stop self.date_filter = _( ('ตั้งแต่วันที่ %s ถึง %s') % (date_start, date_end)) @api.multi def action_get_report(self): action = self.env.ref( 'cmo_account_report.action_xlsx_report_asset_form') action.sudo().write({'context': {'wizard_id': self.id}}) return super(XLSXReportAsset, self).action_get_report() @api.onchange('asset_status') def _onchange_asset_status(self): if self.asset_status: return {'domain': {'asset_ids': [ ('state', '=', self.asset_status)]}} else: return {'domain': {'asset_ids': []}}
class OpPublisher(models.Model): _name = 'op.publisher' name = fields.Char('Name', size=20, required=True) address_id = fields.Many2one('res.partner', 'Address') book_ids = fields.Many2many('op.book', string='Book(s)')
class rappel(models.Model): _inherit = 'rappel' brand_ids = fields.Many2many('product.brand', 'rappel_product_brand_rel', 'rappel_id', 'product_brand_id', 'Brand') discount_voucher = fields.Boolean('Discount voucher') pricelist_ids = fields.Many2many('product.pricelist', 'rappel_product_pricelist_rel', 'rappel_id', 'product_pricelist_id', 'Pricelist') description = fields.Char('Description', translate=True) sequence = fields.Integer('Sequence', default=100) @api.multi def get_products(self): product_obj = self.env['product.product'] product_ids = self.env['product.product'] for rappel in self: if not rappel.global_application: if rappel.product_id: product_ids += rappel.product_id elif rappel.brand_ids: product_ids += product_obj.search([ ('product_brand_id', 'in', rappel.brand_ids.ids) ]) elif rappel.product_categ_id: product_ids += product_obj.search([ ('categ_id', '=', rappel.product_categ_id.id) ]) else: product_ids += product_obj.search([]) return product_ids.ids @api.constrains('global_application', 'product_id', 'brand_ids', 'product_categ_id') def _check_application(self): if not self.global_application and not self.product_id \ and not self.product_categ_id and not self.brand_ids: raise exceptions. \ ValidationError(_('Product, brand and category are empty')) @api.model def update_partner_rappel_pricelist(self): partner_obj = self.env['res.partner'] rappel_obj = self.env['rappel'] partner_rappel_obj = self.env['res.partner.rappel.rel'] now = datetime.now() now_str = now.strftime("%Y-%m-%d") yesterday_str = (now - relativedelta(days=1)).strftime("%Y-%m-%d") end_actual_month = now.strftime("%Y-%m") + '-' + str( monthrange(now.year, now.month)[1]) start_next_month = (now + relativedelta(months=1)).strftime("%Y-%m") + '-01' discount_voucher_rappels = rappel_obj.search([('discount_voucher', '=', True)]) for rappel in discount_voucher_rappels: pricelist_ids = tuple(rappel.pricelist_ids.ids) partner_pricelist = tuple( partner_obj.search([('property_product_pricelist', 'in', pricelist_ids), ('prospective', '=', False), ('active', '=', True), ('is_company', '=', True), ('parent_id', '=', False)]).ids) partner_rappel = tuple( partner_rappel_obj.search([('rappel_id', '=', rappel.id), '|', ('date_end', '=', False), ('date_end', '>=', now_str), ('date_start', '<=', now_str) ]).mapped('partner_id.id')) # Clientes que faltan en el rappel -> Se crean dos entradas en el rappel: # - Una para liquidar en el mes actual # - Otra que empiece en fecha 1 del mes siguiente add_partners = set(partner_pricelist) - set(partner_rappel) if add_partners: new_line1 = { 'rappel_id': rappel.id, 'periodicity': 'monthly', 'date_start': now_str, 'date_end': end_actual_month } new_line2 = { 'rappel_id': rappel.id, 'periodicity': 'monthly', 'date_start': start_next_month } for partner in add_partners: new_line1.update({'partner_id': partner}) partner_rappel_obj.create(new_line1) new_line2.update({'partner_id': partner}) partner_rappel_obj.create(new_line2) # Clientes a los que ya no les corresponde el rappel -> Se actualiza fecha fin con la fecha actual remove_partners = set(partner_rappel) - set(partner_pricelist) if remove_partners: vals = {'date_end': yesterday_str} partner_to_update = partner_rappel_obj.search([ ('rappel_id', '=', rappel.id), ('partner_id', 'in', tuple(remove_partners)), '|', ('date_end', '=', False), ('date_end', '>', now), ('date_start', '<=', now_str) ]) partner_to_update.write(vals) @api.model def compute_rappel(self): if not self.ids: ordered_rappels = self.search([], order='sequence') else: ordered_rappels = self.sorted(key=lambda x: x.sequence) super(rappel, ordered_rappels).compute_rappel()
class ReportEvaluationByTeacherWizard(models.TransientModel): _name = "school_evaluations.report_evaluation_by_teacher" _description = "Evaluations by Teacher Report" year_id = fields.Many2one( 'school.year', string='Year', default=lambda self: self.env.user.current_year_id, ondelete='cascade') teacher_id = fields.Many2one('res.partner', string='Teacher', ondelete='cascade', domain=[('teacher', '=', True)]) teacher_ids = fields.Many2many('res.partner', 'report_evaluation_by_teacher_teacher_rel', 'report_id', 'teacher_id', string='Teachers', ondelete='cascade', domain=[('teacher', '=', True)]) display_results = fields.Boolean(string='Display Current Results') freeze_first_session = fields.Boolean(string='Freeze First Session') message = fields.Text(string="Message") send_as_email = fields.Boolean(string="Send as email") @api.multi def print_report(self, data): self.ensure_one() data['year_id'] = self.year_id.id data['message'] = self.message data['display_results'] = self.display_results data['freeze_first_session'] = self.freeze_first_session if self.send_as_email: for teacher_id in self.teacher_ids: data['teacher_ids'] = [teacher_id.id] self.send_mail(teacher_id, data) else: if self.teacher_id: data['teacher_ids'] = [self.teacher_id.id] elif self.teacher_ids: data['teacher_ids'] = self.teacher_ids.ids else: context = dict(self._context or {}) data['teacher_ids'] = data.get('active_ids') return self.env['report'].get_action( self, 'school_evaluations.report_evaluation_by_teacher_content', data=data) def send_mail(self, teacher_id, data): """Generates a new mail message for the given template and record, and schedules it for delivery through the ``mail`` module's scheduler. :param int res_id: id of the record to render the template with (model is taken from the template) :param bool force_send: if True, the generated mail.message is immediately sent after being created, as if the scheduler was executed for this message only. :returns: id of the mail.message that was created """ self.ensure_one() Mail = self.env['mail.mail'] Attachment = self.env[ 'ir.attachment'] # TDE FIXME: should remove dfeault_type from context template = self.env.ref( 'school_evaluations.mail_template_evaluation_email') for wizard_line in self: if template: # create a mail_mail based on values, without attachments values = template.generate_email(teacher_id.id) values['recipient_ids'] = [(6, 0, [teacher_id.id])] attachment_ids = values.pop('attachment_ids', []) attachments = values.pop('attachments', []) # add a protection against void email_from if 'email_from' in values and not values.get('email_from'): values.pop('email_from') mail = Mail.create(values) # manage attachments filename = "evaluations.pdf" report = self.env.ref( 'school_evaluations.report_evaluation_by_teacher') pdf_bin, _ = report.render_report( [teacher_id.id], 'school_evaluations.report_evaluation_by_teacher_content', data=data) attachment = self.env['ir.attachment'].create({ 'name': filename, 'datas': base64.b64encode(pdf_bin), 'datas_fname': filename, 'res_model': 'res.partner', 'res_id': teacher_id.id, 'type': 'binary', # override default_type from context, possibly meant for another model! }) # for attachment in attachments: # attachment_data = { # 'name': attachment[0], # 'datas_fname': attachment[0], # 'datas': attachment[1], # 'type': 'binary', # 'res_model': 'mail.message', # 'res_id': mail.mail_message_id.id, # } # attachment_ids.append(Attachment.create(attachment_data).id) # if attachment_ids: # values['attachment_ids'] = [(6, 0, attachment_ids)] mail.write({'attachment_ids': [(6, 0, [attachment.id])]}) mail.send() return mail.id # TDE CLEANME: return mail + api.returns ?
class ir_attahment(models.Model): _inherit = 'ir.attachment' tag_ids = fields.Many2many(comodel_name='ir.attachment.tag', string='Tags')
class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' sale_line_ids = fields.Many2many('sale.order.line', 'sale_order_line_invoice_rel', 'invoice_line_id', 'order_line_id', string='Sale Order Lines', readonly=True, copy=False)
class SaleOrderLine(models.Model): _name = 'sale.order.line' _description = 'Sales Order Line' _order = 'order_id desc, sequence, id' @api.depends('state', 'product_uom_qty', 'qty_delivered', 'qty_to_invoice', 'qty_invoiced') def _compute_invoice_status(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for line in self: if line.state not in ('sale', 'done'): line.invoice_status = 'no' elif not float_is_zero(line.qty_to_invoice, precision_digits=precision): line.invoice_status = 'to invoice' elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) == 1 or\ float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) >= 0 and\ float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) == 1: line.invoice_status = 'upselling' elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) == 0: line.invoice_status = 'invoiced' else: line.invoice_status = 'no' @api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id') def _compute_amount(self): for line in self: price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_id) line.update({ 'price_tax': taxes['total_included'] - taxes['total_excluded'], 'price_total': taxes['total_included'], 'price_subtotal': taxes['total_excluded'], }) @api.depends('product_id.invoice_policy', 'order_id.state') def _compute_qty_delivered_updateable(self): for line in self: line.qty_delivered_updateable = line.product_id.invoice_policy in ('order', 'delivery') and line.order_id.state == 'sale' @api.depends('qty_invoiced', 'qty_delivered', 'product_uom_qty', 'order_id.state') def _get_to_invoice_qty(self): for line in self: if line.order_id.state in ['sale', 'done']: if line.product_id.invoice_policy == 'order': line.qty_to_invoice = line.product_uom_qty - line.qty_invoiced else: line.qty_to_invoice = line.qty_delivered - line.qty_invoiced else: line.qty_to_invoice = 0 @api.depends('invoice_lines.invoice_id.state', 'invoice_lines.quantity') def _get_invoice_qty(self): for line in self: qty_invoiced = 0.0 for invoice_line in line.invoice_lines: if invoice_line.invoice_id.state != 'cancel': if invoice_line.invoice_id.type == 'out_invoice': qty_invoiced += invoice_line.quantity elif invoice_line.invoice_id.type == 'out_refund': qty_invoiced -= invoice_line.quantity line.qty_invoiced = qty_invoiced @api.depends('price_subtotal', 'product_uom_qty') def _get_price_reduce(self): for line in self: line.price_reduce = line.price_subtotal / line.product_uom_qty if line.product_uom_qty else 0.0 @api.multi @api.onchange('order_id', 'product_id') def _compute_tax_id(self): for line in self: fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id if fpos: # The superuser is used by website_sale in order to create a sale order. We need to make # sure we only select the taxes related to the company of the partner. This should only # apply if the partner is linked to a company. if self.env.uid == SUPERUSER_ID and line.order_id.company_id: taxes = fpos.map_tax(line.product_id.taxes_id).filtered(lambda r: r.company_id == line.order_id.company_id) else: taxes = fpos.map_tax(line.product_id.taxes_id) line.tax_id = taxes else: line.tax_id = False @api.multi def _prepare_order_line_procurement(self, group_id=False): self.ensure_one() return { 'name': self.name, 'origin': self.order_id.name, 'date_planned': datetime.strptime(self.order_id.date_order, DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(days=self.customer_lead), 'product_id': self.product_id.id, 'product_qty': self.product_uom_qty, 'product_uom': self.product_uom.id, 'company_id': self.order_id.company_id.id, 'group_id': group_id, 'sale_line_id': self.id } @api.multi def _action_procurement_create(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for line in self: if line.state != 'sale': continue qty = 0.0 for proc in line.procurement_ids: qty += proc.product_qty if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0: return False if not line.order_id.procurement_group_id: vals = line.order_id._prepare_procurement_group() line.order_id.procurement_group_id = self.env["procurement.group"].create(vals) vals = line._prepare_order_line_procurement(group_id=line.order_id.procurement_group_id.id) vals['product_qty'] = line.product_uom_qty - qty new_proc = self.env["procurement.order"].create(vals) new_proc.run() return True @api.model def _get_analytic_invoice_policy(self): return ['cost'] @api.model def _get_analytic_track_service(self): return [] # Create new procurements if quantities purchased changes @api.model def create(self, values): line = super(SaleOrderLine, self).create(values) if line.state == 'sale': if line.product_id.track_service in self._get_analytic_track_service() or line.product_id.invoice_policy in self._get_analytic_invoice_policy() and not line.order_id.project_id: line.order_id._create_analytic_account() line._action_procurement_create() return line # Create new procurements if quantities purchased changes @api.multi def write(self, values): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') lines = False if 'product_uom_qty' in values: lines = self.filtered( lambda r: r.state == 'sale' and float_compare(r.product_uom_qty, values['product_uom_qty'], precision_digits=precision) == -1) lines._action_procurement_create() return super(SaleOrderLine, self).write(values) order_id = fields.Many2one('sale.order', string='Order Reference', required=True, ondelete='cascade', index=True, copy=False) name = fields.Text(string='Description', required=True) sequence = fields.Integer(string='Sequence', default=10) invoice_lines = fields.Many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_line_id', string='Invoice Lines', copy=False) invoice_status = fields.Selection([ ('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice') ], string='Invoice Status', compute='_compute_invoice_status', store=True, readonly=True, default='no') price_unit = fields.Float('Unit Price', required=True, digits_compute=dp.get_precision('Product Price'), default=0.0) price_subtotal = fields.Monetary(compute='_compute_amount', string='Subtotal', readonly=True, store=True) price_tax = fields.Monetary(compute='_compute_amount', string='Taxes', readonly=True, store=True) price_total = fields.Monetary(compute='_compute_amount', string='Total', readonly=True, store=True) price_reduce = fields.Monetary(compute='_get_price_reduce', string='Price Reduce', readonly=True, store=True) tax_id = fields.Many2many('account.tax', string='Taxes', readonly=True, states={'draft': [('readonly', False)]}) discount = fields.Float(string='Discount (%)', digits_compute=dp.get_precision('Discount'), default=0.0) product_id = fields.Many2one('product.product', string='Product', domain=[('sale_ok', '=', True)], change_default=True, ondelete='restrict', required=True) product_uom_qty = fields.Float(string='Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True, default=1.0) product_uom = fields.Many2one('product.uom', string='Unit of Measure', required=True) qty_delivered_updateable = fields.Boolean(compute='_compute_qty_delivered_updateable', string='Can Edit Delivered', readonly=True, default=True) qty_delivered = fields.Float(string='Delivered', copy=False, digits_compute=dp.get_precision('Product Unit of Measure'), default=0.0) qty_to_invoice = fields.Float( compute='_get_to_invoice_qty', string='To Invoice', store=True, readonly=True, digits_compute=dp.get_precision('Product Unit of Measure'), default=0.0) qty_invoiced = fields.Float( compute='_get_invoice_qty', string='Invoiced', store=True, readonly=True, digits_compute=dp.get_precision('Product Unit of Measure'), default=0.0) salesman_id = fields.Many2one(related='order_id.user_id', store=True, string='Salesperson', readonly=True) currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True) company_id = fields.Many2one(related='order_id.company_id', string='Company', store=True, readonly=True) order_partner_id = fields.Many2one(related='order_id.partner_id', store=True, string='Customer') state = fields.Selection([ ('draft', 'Quotation'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Done'), ('cancel', 'Cancelled'), ], related='order_id.state', string='Order Status', readonly=True, copy=False, store=True, default='draft') customer_lead = fields.Float( 'Delivery Lead Time', required=True, default=0.0, help="Number of days between the order confirmation and the shipping of the products to the customer", oldname="delay") procurement_ids = fields.One2many('procurement.order', 'sale_line_id', string='Procurements') @api.multi def _prepare_invoice_line(self, qty): """Prepare the dict of values to create the new invoice line for a sales order line. This method may be overridden to implement custom invoice generation (making sure to call super() to establish a clean extension chain). :param qty : float quantity to invoice """ self.ensure_one() res = {} account_id = self.product_id.property_account_income_id.id or self.product_id.categ_id.property_account_income_categ_id.id if not account_id: raise UserError(_('Please define income account for this product: "%s" (id:%d) - or for its category: "%s".') % \ (self.product_id.name, self.product_id.id, self.product_id.categ_id.name)) fpos = self.order_id.fiscal_position_id or self.order_id.partner_id.property_account_position_id if fpos: account_id = self.order_id.fiscal_position_id.map_account(account_id) res = { 'name': self.name, 'sequence': self.sequence, 'origin': self.order_id.name, 'account_id': account_id, 'price_unit': self.price_unit, 'quantity': qty, 'discount': self.discount, 'uom_id': self.product_uom.id, 'product_id': self.product_id.id or False, 'invoice_line_tax_ids': [(6, 0, self.tax_id.ids)], 'account_analytic_id': self.order_id.project_id.id, } return res @api.multi def invoice_line_create(self, invoice_id, qty): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for line in self: if not float_is_zero(qty, precision_digits=precision): vals = line._prepare_invoice_line(qty=qty) vals.update({'invoice_id': invoice_id, 'sale_line_ids': [(6, 0, [line.id])]}) self.env['account.invoice.line'].create(vals) @api.multi @api.onchange('product_id') def product_id_change(self): if not self.product_id: return {'domain': {'product_uom': []}} vals = {} domain = {'product_uom': [('category_id', '=', self.product_id.uom_id.category_id.id)]} if not (self.product_uom and (self.product_id.uom_id.category_id.id == self.product_uom.category_id.id)): vals['product_uom'] = self.product_id.uom_id product = self.product_id.with_context( lang=self.order_id.partner_id.lang, partner=self.order_id.partner_id.id, quantity=self.product_uom_qty, date=self.order_id.date_order, pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id ) name = product.name_get()[0][1] if product.description_sale: name += '\n' + product.description_sale vals['name'] = name if self.order_id.pricelist_id and self.order_id.partner_id: vals['price_unit'] = product.price self.update(vals) return {'domain': domain} @api.onchange('product_uom') def product_uom_change(self): if not self.product_uom: self.price_unit = 0.0 return if self.order_id.pricelist_id and self.order_id.partner_id: product = self.product_id.with_context( lang=self.order_id.partner_id.lang, partner=self.order_id.partner_id.id, quantity=self.product_uom_qty, date_order=self.order_id.date_order, pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id ) self.price_unit = product.price @api.multi def unlink(self): if self.filtered(lambda x: x.state in ('sale', 'done')): raise UserError(_('You can not remove a sale order line.\nDiscard changes and try setting the quantity to 0.')) return super(SaleOrderLine, self).unlink() @api.multi def _get_delivered_qty(self): ''' Intended to be overridden in sale_stock and sale_mrp :return: the quantity delivered :rtype: float ''' return 0.0
class SaleOrder(models.Model): _name = "sale.order" _inherit = ['mail.thread', 'ir.needaction_mixin'] _description = "Sales Order" _order = 'date_order desc, id desc' @api.depends('order_line.product_uom_qty', 'order_line.discount', 'order_line.price_unit', 'order_line.tax_id') def _amount_all(self): amount_untaxed = amount_tax = 0.0 for line in self.order_line: amount_untaxed += line.price_subtotal amount_tax += line.price_tax self.update({ 'amount_untaxed': self.pricelist_id.currency_id.round(amount_untaxed), 'amount_tax': self.pricelist_id.currency_id.round(amount_tax), 'amount_total': amount_untaxed + amount_tax, }) @api.depends('state', 'order_line.invoice_status') def _get_invoiced(self): for order in self: invoice_ids = order.order_line.mapped('invoice_lines').mapped('invoice_id').ids if order.state not in ('sale', 'done'): invoice_status = 'no' elif any(line.invoice_status == 'to invoice' for line in order.order_line): invoice_status = 'to invoice' elif all(line.invoice_status == 'invoiced' for line in order.order_line): invoice_status = 'invoiced' elif all(line.invoice_status in ['invoiced', 'upselling'] for line in order.order_line): invoice_status = 'upselling' else: invoice_status = 'no' order.update({ 'invoice_count': len(set(invoice_ids)), 'invoice_ids': invoice_ids, 'invoice_status': invoice_status }) @api.model def _default_note(self): return self.env.user.company_id.sale_note @api.model def _get_default_team(self): default_team_id = self.env['crm.team']._get_default_team_id() return self.env['crm.team'].browse(default_team_id) @api.onchange('fiscal_position_id') def _compute_tax_id(self): for order in self: order.order_line._compute_tax_id() name = fields.Char(string='Order Reference', required=True, copy=False, readonly=True, index=True, default='New') origin = fields.Char(string='Source Document', help="Reference of the document that generated this sales order request.") client_order_ref = fields.Char(string='Customer Reference', copy=False) state = fields.Selection([ ('draft', 'Quotation'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Done'), ('cancel', 'Cancelled'), ], string='Status', readonly=True, copy=False, index=True, default='draft') date_order = fields.Datetime(string='Order Date', required=True, readonly=True, index=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=False, default=fields.Date.context_today) validity_date = fields.Date(string='Expiration Date', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}) create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.") user_id = fields.Many2one('res.users', string='Salesperson', index=True, track_visibility='onchange', default=lambda self: self.env.user) partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, required=True, change_default=True, index=True, track_visibility='always') partner_invoice_id = fields.Many2one('res.partner', string='Invoice Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Invoice address for current sales order.") partner_shipping_id = fields.Many2one('res.partner', string='Delivery Address', readonly=True, required=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Delivery address for current sales order.") pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="Pricelist for current sales order.") currency_id = fields.Many2one("res.currency", related='pricelist_id.currency_id', string="Currency", readonly=True, required=True) project_id = fields.Many2one('account.analytic.account', 'Analytic Account', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="The analytic account related to a sales order.", copy=False) order_line = fields.One2many('sale.order.line', 'order_id', string='Order Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True) invoice_count = fields.Integer(string='# of Invoices', compute='_get_invoiced', store=True, readonly=True) invoice_ids = fields.Many2many("account.invoice", string='Invoices', compute="_get_invoiced", readonly=True, copy=False) invoice_status = fields.Selection([ ('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice') ], string='Invoice Status', compute='_get_invoiced', store=True, readonly=True, default='no') note = fields.Text('Terms and conditions', default=_default_note) amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', track_visibility='always') amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all', track_visibility='always') amount_total = fields.Monetary(string='Total', store=True, readonly=True, compute='_amount_all', track_visibility='always') payment_term_id = fields.Many2one('account.payment.term', string='Payment Term', oldname='payment_term') fiscal_position_id = fields.Many2one('account.fiscal.position', oldname='fiscal_position', string='Fiscal Position') company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env['res.company']._company_default_get('sale.order')) team_id = fields.Many2one('crm.team', 'Sales Team', change_default=True, default=_get_default_team) procurement_group_id = fields.Many2one('procurement.group', 'Procurement Group', copy=False) product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') @api.multi def button_dummy(self): return True @api.multi def unlink(self): for order in self: if order.state != 'draft': raise UserError(_('You can only delete draft quotations!')) return super(SaleOrder, self).unlink() @api.multi def _track_subtype(self, init_values): self.ensure_one() if 'state' in init_values and self.state == 'sale': return 'sale.mt_order_confirmed' elif 'state' in init_values and self.state == 'sent': return 'sale.mt_order_sent' return super(SaleOrder, self)._track_subtype(init_values) @api.onchange('partner_shipping_id') def onchange_partner_shipping_id(self): fiscal_position = self.env['account.fiscal.position'].get_fiscal_position(self.partner_id.id, self.partner_shipping_id.id) if fiscal_position: self.fiscal_position_id = fiscal_position return {} @api.multi @api.onchange('partner_id') def onchange_partner_id(self): if not self.partner_id: self.update({ 'partner_invoice_id': False, 'partner_shipping_id': False, 'payment_term_id': False, 'fiscal_position_id': False, }) return addr = self.partner_id.address_get(['delivery', 'invoice']) values = { 'pricelist_id': self.partner_id.property_product_pricelist and self.partner_id.property_product_pricelist.id or False, 'payment_term_id': self.partner_id.property_payment_term_id and self.partner_id.property_payment_term_id.id or False, 'partner_invoice_id': addr['invoice'], 'partner_shipping_id': addr['delivery'], } if self.partner_id.user_id: values['user_id'] = self.partner_id.user_id.id if self.partner_id.team_id: values['team_id'] = self.partner_id.team_id.id self.update(values) @api.model def create(self, vals): if vals.get('name', 'New') == 'New': vals['name'] = self.env['ir.sequence'].next_by_code('sale.order') or 'New' if any(f not in vals for f in ['partner_invoice_id', 'partner_shipping_id', 'pricelist_id']): partner = self.env['res.partner'].browse(vals.get('partner_id')) addr = partner.address_get(['delivery', 'invoice']) vals['partner_invoice_id'] = vals.setdefault('partner_invoice_id', addr['invoice']) vals['partner_shipping_id'] = vals.setdefault('partner_shipping_id', addr['delivery']) vals['pricelist_id'] = vals.setdefault('pricelist_id', partner.property_product_pricelist and partner.property_product_pricelist.id) result = super(SaleOrder, self).create(vals) self.message_post(body=_("Quotation created")) return result @api.multi def _prepare_invoice(self): """Prepare the dict of values to create the new invoice for a sales order. This method may be overridden to implement custom invoice generation (making sure to call super() to establish a clean extension chain). """ self.ensure_one() journal_ids = self.env['account.journal'].search([('type', '=', 'sale'), ('company_id', '=', self.company_id.id)], limit=1) if not journal_ids: raise UserError(_('Please define an accounting sale journal for this company.')) invoice_vals = { 'name': self.client_order_ref or '', 'origin': self.name, 'type': 'out_invoice', 'reference': self.client_order_ref or self.name, 'account_id': self.partner_invoice_id.property_account_receivable_id.id, 'partner_id': self.partner_invoice_id.id, 'journal_id': journal_ids[0].id, 'currency_id': self.pricelist_id.currency_id.id, 'comment': self.note, 'payment_term_id': self.payment_term_id.id, 'fiscal_position_id': self.fiscal_position_id.id or self.partner_invoice_id.property_account_position_id.id, 'company_id': self.company_id.id, 'user_id': self.user_id and self.user_id.id, 'team_id': self.team_id.id } return invoice_vals @api.multi def print_quotation(self): self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'}) return self.env['report'].get_action(self, 'sale.report_saleorder') @api.multi def action_view_invoice(self): self.ensure_one() imd = self.env['ir.model.data'] action = imd.xmlid_to_object('account.action_invoice_tree1') list_view_id = imd.xmlid_to_res_id('account.invoice_tree') form_view_id = imd.xmlid_to_res_id('account.invoice_form') result = { 'name': action.name, 'help': action.help, 'type': action.type, 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], [False, 'calendar'], [False, 'pivot']], 'target': action.target, 'context': action.context, 'res_model': action.res_model, } if len(self.invoice_ids) > 1: result['domain'] = "[('id','in',%s)]" % self.invoice_ids.ids elif len(self.invoice_ids) == 1: result['views'] = [(form_view_id, 'form')] result['res_id'] = self.invoice_ids.id else: result = {'type': 'ir.actions.act_window_close'} return result @api.multi def action_invoice_create(self, grouped=False, final=False): inv_obj = self.env['account.invoice'] precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') invoices = {} for order in self: group_key = order.id if grouped else (order.partner_id.id, order.currency_id.id) for line in order.order_line.sorted(key=lambda l: l.qty_to_invoice < 0): if float_is_zero(line.qty_to_invoice, precision_digits=precision): continue if group_key not in invoices: inv_data = order._prepare_invoice() invoice = inv_obj.create(inv_data) invoices[group_key] = invoice if line.qty_to_invoice > 0: line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice) elif line.qty_to_invoice < 0 and (final or invoices[group_key].amount_untaxed > abs(line.qty_to_invoice * line.price_unit)): line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice) for invoice in invoices.values(): # If invoice is negative, do a refund invoice instead if invoice.amount_untaxed < 0: invoice.type = 'out_refund' for line in invoice.invoice_line_ids: line.quantity = -line.quantity # Necessary to force computation of taxes. In account_invoice, they are triggered # by onchanges, which are not triggered when doing a create. invoice.compute_taxes() return [inv.id for inv in invoices.values()] @api.multi def action_draft(self): self.filtered(lambda s: s.state in ['cancel', 'sent']).write({'state': 'draft'}) @api.multi def action_cancel(self): self.write({'state': 'cancel'}) @api.multi def action_quotation_send(self): ''' This function opens a window to compose an email, with the edi sale template message loaded by default ''' self.ensure_one() ir_model_data = self.env['ir.model.data'] try: template_id = ir_model_data.get_object_reference('sale', 'email_template_edi_sale')[1] except ValueError: template_id = False try: compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1] except ValueError: compose_form_id = False ctx = dict() ctx.update({ 'default_model': 'sale.order', 'default_res_id': self.ids[0], 'default_use_template': bool(template_id), 'default_template_id': template_id, 'default_composition_mode': 'comment', 'mark_so_as_sent': True }) return { 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', 'res_model': 'mail.compose.message', 'views': [(compose_form_id, 'form')], 'view_id': compose_form_id, 'target': 'new', 'context': ctx, } @api.multi def force_quotation_send(self): for order in self: email_act = order.action_quotation_send() if email_act and email_act.get('context'): email_ctx = email_act['context'] email_ctx.update(default_email_from=order.company_id.email) order.with_context(email_ctx).message_post_with_template(email_ctx.get('default_template_id')) return True @api.multi def action_done(self): self.write({'state': 'done'}) @api.model def _prepare_procurement_group(self): return {'name': self.name} @api.multi def action_confirm(self): for order in self: order.state = 'sale' order.order_line._action_procurement_create() if not order.project_id: for line in order.order_line: if line.product_id.invoice_policy == 'cost': order._create_analytic_account() break @api.multi def _create_analytic_account(self, prefix=None): for order in self: name = order.name if prefix: name = prefix + ": " + order.name analytic = self.env['account.analytic.account'].create({ 'name': name, 'code': order.client_order_ref, 'company_id': order.company_id.id, 'partner_id': order.partner_id.id }) order.project_id = analytic
class Encounter(models.Model): _name = "hc.res.encounter" _description = "Encounter" identifier_ids = fields.One2many( comodel_name="hc.encounter.identifier", inverse_name="encounter_id", string="Identifiers", help="Identifier(s) by which this encounter is known.") status = fields.Selection(string="Encounter Status", required="True", selection=[("planned", "Planned"), ("arrived", "Arrived"), ("in-progress", "In-Progress"), ("onleave", "On Leave"), ("finished", "Finished"), ("cancelled", "Cancelled")], help="Current state of the encounter.") encounter_class = fields.Selection(string="Encounter Class", selection=[("inpatient", "Inpatient"), ("outpatient", "Outpatient"), ("ambulatory", "Ambulatory"), ("emergency", "Emergency")], help="Classification of the encounter.") type_ids = fields.Many2many(comodel_name="hc.vs.encounter.type", string="Types", help="Specific type of encounter.") priority_id = fields.Many2one( comodel_name="hc.vs.act.priority", string="Priority", help="Indicates the urgency of the encounter.") patient_id = fields.Many2one(comodel_name="hc.res.patient", string="Patient", help="The patient present at the encounter.") episode_of_care_ids = fields.One2many( comodel_name="hc.encounter.episode.of.care", inverse_name="encounter_id", string="Episodes of Care", help= "Episode(s) of care that this encounter should be recorded against.") incoming_referral_ids = fields.One2many( comodel_name="hc.encounter.referral.request", inverse_name="encounter_id", string="Incoming Referrals", help="The ReferralRequest that initiated this encounter.") # appointment_id = fields.Many2one( # comodel_name="hc.res.appointment", # string="Appointment", # help="The appointment that scheduled this encounter.") start_date = fields.Datetime(string="Start Date", help="Start of the encounter.") end_date = fields.Datetime(string="End Date", help="End of the encounter.") length_uom_id = fields.Many2one( comodel_name="hc.vs.uom", string="Length UOM", help= "Quantity of time the encounter lasted (less time absent) unit of measure." ) length = fields.Float( string="Length", help="Quantity of time the encounter lasted (less time absent).") reason_ids = fields.Many2many( comodel_name="hc.vs.encounter.reason", string="Reasons", help="Reason the encounter takes place (code).") indication_ids = fields.One2many( comodel_name="hc.encounter.indication", inverse_name="encounter_id", string="Indications", help="Reason the encounter takes place (resource).") account_ids = fields.One2many( comodel_name="hc.encounter.account", inverse_name="encounter_id", string="Accounts", help= "The set of accounts that may be used for billing for this Encounter.") service_provider_id = fields.Many2one( comodel_name="hc.res.organization", string="Service Provider", help="The custodian organization of this Encounter record.") part_of_id = fields.Many2one( comodel_name="hc.res.encounter", string="Part Of", help="Another Encounter this encounter is part of.") status_history_ids = fields.One2many( comodel_name="hc.encounter.status.history", inverse_name="encounter_id", string="Status History", help="List of Encounter statuses.") participant_ids = fields.One2many( comodel_name="hc.encounter.participant", inverse_name="encounter_id", string="Participants", help="List of participants involved in the encounter.") hospitalization_ids = fields.One2many( comodel_name="hc.encounter.hospitalization", inverse_name="encounter_id", string="Hospitalizations", help="Details about an admission to a clinic.") location_ids = fields.One2many( comodel_name="hc.encounter.location", inverse_name="encounter_id", string="Locations", help="List of locations the patient has been at.")
class FinancieraSmsMessageMasive(models.Model): _name = 'financiera.sms.message.masive' _order = 'id desc' name = fields.Char("Nombre") partner_ids = fields.Many2many('res.partner', 'financiera_partner_messagemasive_rel', 'partner_id', 'masivemessage_id', string='Destinatarios') template_id = fields.Many2one('financiera.sms.message.masive.template', 'Plantilla') tipo = fields.Char('Tipo de mensaje') body_count_available = fields.Integer( 'Caracteres restantes', compute='_compute_body_count_available') body = fields.Text('Mensaje', size=160) is_html = fields.Boolean('Adjuntar html') html = fields.Text('Html') company_id = fields.Many2one('res.company', 'Empresa') message_ids = fields.One2many('financiera.sms.message', 'sms_message_masive_id', 'Mensajes') state = fields.Selection([('draft', 'Borrador'), ('send', 'Enviado')], string='Estado', readonly=True, default='draft') @api.model def create(self, values): rec = super(FinancieraSmsMessageMasive, self).create(values) sms_masivo_count = rec.company_id.sms_configuracion_id.sms_message_masive_count rec.update({ 'name': 'SMS MASIVO/' + str(sms_masivo_count).zfill(6), }) rec.company_id.sms_configuracion_id.sms_message_masive_count = sms_masivo_count + 1 return rec @api.model def default_get(self, fields): rec = super(FinancieraSmsMessageMasive, self).default_get(fields) # configuracion_id = self.env.user.company_id.configuracion_id context = dict(self._context or {}) current_uid = context.get('uid') current_user = self.env['res.users'].browse(current_uid) company_id = current_user.company_id rec.update({ 'company_id': company_id.id, }) return rec @api.onchange('body', 'is_html') def _compute_body_count_available(self): if self.body: if not self.is_html: self.body_count_available = 160 - len(self.body) else: self.body_count_available = 137 - len(self.body) else: if not self.is_html: self.body_count_available = 160 else: self.body_count_available = 137 @api.constrains('body', 'is_html') def _check_body(self): if self.body: if self.body_count_available < 0: raise UserError("Debe borrar al menos %s caracteres." % str(abs(self.body_count_available))) @api.onchange('template_id') def _onchange_template_id(self): if self.template_id.tipo: self.tipo = self.template_id.tipo if self.template_id.body: self.body = self.template_id.body @api.one def partners_deseleccionar(self): self.partner_ids = [(6, 0, [])] # @api.one # def partners_cuota_preventiva(self): # cr = self.env.cr # uid = self.env.uid # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('state_mora', '=', 'preventiva'), # ('state', '=', 'activa')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] # @api.one # def partners_cuota_vencida(self): # cr = self.env.cr # uid = self.env.uid # fecha_actual = datetime.now() # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('fecha_vencimiento', '<', fecha_actual), # ('state', '=', 'activa')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] # @api.one # def partners_cuota_vencida_moraTemprana(self): # cr = self.env.cr # uid = self.env.uid # fecha_actual = datetime.now() # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('fecha_vencimiento', '<', fecha_actual), # ('state', '=', 'activa'), # ('state_mora', '=', 'moraTemprana')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] # @api.one # def partners_cuota_vencida_moraMedia(self): # cr = self.env.cr # uid = self.env.uid # fecha_actual = datetime.now() # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('fecha_vencimiento', '<', fecha_actual), # ('state', '=', 'activa'), # ('state_mora', '=', 'moraMedia')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] # @api.one # def partners_cuota_vencida_moraTardia(self): # cr = self.env.cr # uid = self.env.uid # fecha_actual = datetime.now() # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('fecha_vencimiento', '<', fecha_actual), # ('state', '=', 'activa'), # ('state_mora', '=', 'moraTardia')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] # @api.one # def partners_cuota_vencida_incobrable(self): # cr = self.env.cr # uid = self.env.uid # fecha_actual = datetime.now() # cuota_obj = self.pool.get('financiera.prestamo.cuota') # cuota_ids = cuota_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('fecha_vencimiento', '<', fecha_actual), # ('state', '=', 'activa'), # ('state_mora', '=', 'incobrable')]) # partner_obj = self.pool.get('res.partner') # partner_ids = partner_obj.search(cr, uid, [ # ('company_id', '=', self.company_id.id), # ('cuota_ids.id', 'in', cuota_ids)]) # self.partner_ids = [(6, 0, partner_ids)] @api.one def send_messages(self): if len(self.partner_ids) > 0: config_id = self.company_id.sms_configuracion_id for partner_id in self.partner_ids: sms_message_values = { 'partner_id': partner_id.id, 'config_id': config_id.id, 'to': partner_id.mobile, 'tipo': self.tipo or 'Personalizado', 'company_id': self.company_id.id, } message_id = self.env['financiera.sms.message'].create( sms_message_values) message_id.body = self.body if self.is_html: message_id.html = self.html message_id.send() self.message_ids = [message_id.id] self.state = 'send' else: raise UserError("Debe agregar al menos un destinatario.")
class HrExpenseExpense(models.Model): _inherit = 'hr.expense.expense' level_id = fields.Many2one( 'level.validation', string='Validation Level', track_visibility='onchange', copy=False, ) approver_ids = fields.Many2many( 'res.users', 'hr_approver_rel', 'expense_id', 'user_id', string='Approver', track_visibility='onchange', copy=False, ) approve_permission = fields.Boolean( string='Approve Permission', compute='_compute_approve_permission', ) state = fields.Selection( selection=[ ('draft', 'New'), ('cancelled', 'Refused'), ('confirm', 'Waiting Approval'), ('validate', 'Waiting Validate'), ('accepted', 'Approved'), ('done', 'Waiting Payment'), ('paid', 'Paid'), ], ) @api.multi def action_check_approval(self): self.ensure_one() amount = self.amount doctype = '' if self.is_employee_advance: doctype = 'employee_advance' elif self.is_advance_clearing: doctype = 'employee_clearing' elif self.pay_to == 'pettycash': doctype = 'employee_pettycash' elif not self.is_advance_clearing and not self.is_employee_advance: doctype = 'employee_expense' levels = self.env['level.validation'].search([ ('operating_unit_id', '=', self.operating_unit_id.id), ('doctype', 'like', doctype), ]).sorted(key=lambda r: r.level) if not levels: raise ValidationError(_("This operating unit does not " "set approver.")) levels_lt_amount = levels.filtered( lambda r: r.limit_amount < amount) levels_gt_amount = levels.filtered( lambda r: r.limit_amount >= amount) if levels_gt_amount: target_levels = levels_lt_amount + levels.filtered( lambda r: r.level == min(levels_gt_amount.mapped('level'))) else: target_levels = levels_lt_amount if not target_levels.filtered( lambda r: r.limit_amount >= amount): raise ValidationError(_("Amount is over " "maximum limited amount.")) if self.approver_ids and self.env.user not in self.approver_ids: raise ValidationError(_("Your user is not allow to " "approve this document.")) if target_levels: if self.level_id: min_level = min(filter(lambda r: r >= self.level_id.level, target_levels.mapped('level'))) target_level = target_levels.filtered( lambda r: r.level == min_level + 1) if target_level: self.write({ 'level_id': target_level.id, 'approver_ids': [ (6, 0, target_level.user_ids.ids) ], }) else: self.write({ 'level_id': False, 'approver_ids': False, }) else: if not self.level_id and not self.approver_ids: target_level = target_levels.filtered( lambda r: r.level == min(target_levels.mapped('level')) ) self.write({ 'level_id': target_level.id, 'approver_ids': [ (6, 0, target_level.user_ids.ids) ], }) return True @api.depends('approver_ids') def _compute_approve_permission(self): for order in self: order.approve_permission = \ bool(self.env.user in order.approver_ids) @api.multi def action_validated(self): self.ensure_one() return self.write({'state': 'validate'}) @api.multi def expense_accept(self): self.ensure_one() res = super(HrExpenseExpense, self).expense_accept() product_lines = self.env['hr.expense.line'].search([ ('expense_id', '=', self.id) ]).mapped('product_id') hr_categories = self.env['product.category'].search([('hr_product', '=', True)]) hr_products = product_lines.filtered( lambda r: r.categ_id in hr_categories ) group_hr = self.env.ref('hr.group_validate_hr_product') if hr_products and self.env.user not in group_hr.users: raise ValidationError( _("You are not allowed to validate document with HR Product.")) return res
class IrUiMenu(models.Model): _name = 'builder.ir.ui.menu' _rec_name = 'complete_name' @api.multi def get_user_roots(self): """ Return all root menu ids visible for the user. :return: the root menu ids :rtype: list(int) """ menu_domain = [('parent_id', '=', False), ('parent_ref', '=', False)] return self.search(menu_domain) @api.multi def load_menus_root(self): menu_roots = self.get_user_roots() return { 'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children': menu_roots, 'all_menu_ids': [i.id for i in menu_roots], } def _get_full_name(self, cr, uid, ids, name=None, args=None, context=None): if context is None: context = {} res = {} for elmt in self.browse(cr, uid, ids, context=context): res[elmt.id] = self._get_one_full_name(elmt) return res def _get_one_full_name(self, elmt, level=6): if level <= 0: return '...' if elmt.parent_id: parent_path = self._get_one_full_name( elmt.parent_id, level - 1) + MENU_ITEM_SEPARATOR else: parent_path = '' return parent_path + elmt.name @api.onchange('parent_ref') def onchange_parent_ref(self): self.parent_menu_id = False if self.parent_ref: self.parent_menu_id = self.env['ir.model.data'].xmlid_to_res_id( self.parent_ref) @api.onchange('parent_menu_id') def onchange_parent_menu_id(self): if self.parent_menu_id: data = self.env['ir.model.data'].search([ ('model', '=', 'ir.ui.menu'), ('res_id', '=', self.parent_menu_id.id) ]) self.parent_ref = "{module}.{id}".format( module=data.module, id=data.name) if data.id else False @api.onchange('parent_type') def onchange_parent_type(self): self.parent_ref = False self.parent_menu_id = False self.parent_id = False module_id = fields.Many2one('builder.ir.module.module', 'Module', ondelete='cascade') name = fields.Char('Menu', required=True, translate=True) xml_id = fields.Char('XML ID', required=True) complete_name = fields.Char('Complete Name', compute='_compute_complete_name') morder = fields.Integer('Order') sequence = fields.Integer('Sequence') child_ids = fields.One2many('builder.ir.ui.menu', 'parent_id', 'Child Ids', copy=True) # group_ids = fields.Many2many('builder.res.groups', 'builder_ir_ui_menu_group_rel', 'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\ # "If this field is empty, Odoo will compute visibility based on the related object's read access.") parent_menu_id = fields.Many2one('ir.ui.menu', 'System Menu', ondelete='set null') parent_ref = fields.Char('System Menu Ref', select=True) parent_id = fields.Many2one('builder.ir.ui.menu', 'Parent Menu', select=True, ondelete='cascade') parent_type = fields.Selection([('module', 'Module'), ('system', 'System')], 'Parent Type') parent_left = fields.Integer('Parent Left', select=True) parent_right = fields.Integer('Parent Left', select=True) action_type = fields.Selection([('module', 'Module'), ('system', 'System')], 'Action Type') action_system_ref = fields.Char('Action System Ref') action_system = fields.Reference([ ('ir.actions.report.xml', 'ir.actions.report.xml'), ('ir.actions.act_window', 'ir.actions.act_window'), ('ir.actions.wizard', 'ir.actions.wizard'), ('ir.actions.act_url', 'ir.actions.act_url'), ('ir.actions.server', 'ir.actions.server'), ('ir.actions.client', 'ir.actions.client'), ], 'System Action') action_module = fields.Reference( [ ('builder.ir.actions.act_window', 'Window'), # ('builder.ir.actions.act_url', 'URL'), ], 'Module Action') group_ids = fields.Many2many( 'builder.res.groups', 'builder_ir_ui_menu_group_rel', 'menu_id', 'gid', string='Groups', help= "If this field is empty, the menu applies to all users. Otherwise, the view applies to the users of those groups only." ) @api.onchange('action_system') def onchange_action_system(self): if self.action_system: model, res_id = self.action_system._name, self.action_system.id data = self.env['ir.model.data'].search([('model', '=', model), ('res_id', '=', res_id)]) self.action_system_ref = "{module}.{id}".format( module=data.module, id=data.name) if data.id else False self.name = self.action_system.name self.xml_id = "menu_{action}".format( action=self.action_system_ref.replace('.', '_')) @api.onchange('action_module') def onchange_action_module(self): if self.action_module: self.name = self.action_module.name self.xml_id = "menu_{action}".format( action=self.action_module.xml_id) @api.model @api.returns('self', lambda value: value.id) def create(self, vals): if not vals.get('parent_type', False): vals['parent_id'] = False vals['parent_menu_id'] = False vals['parent_ref'] = False return super(IrUiMenu, self).create(vals) @api.multi def write(self, vals): if not vals.get('parent_type', self.parent_type): vals['parent_id'] = False vals['parent_menu_id'] = False vals['parent_ref'] = False return super(IrUiMenu, self).write(vals) @api.one def _compute_complete_name(self): self.complete_name = self._get_full_name_one() @api.multi def _get_full_name_one(self, level=6): if level <= 0: return '...' parent_path = '' if self.parent_id: parent_path = self.parent_id._get_full_name_one( level - 1) + MENU_ITEM_SEPARATOR elif self.parent_ref: parent_path = _('[INHERITED]') + MENU_ITEM_SEPARATOR if self.parent_menu_id: parent_path = '[{name}]'.format( name=self.parent_menu_id.complete_name ) + MENU_ITEM_SEPARATOR else: parent_path = '[{ref}]'.format( ref=self.parent_ref) + MENU_ITEM_SEPARATOR return parent_path + self.name @api.one def name_get(self): return self.id, self._get_full_name_one() def _rec_message(self, cr, uid, ids, context=None): return _('Error ! You can not create recursive Menu.') _constraints = [(osv.osv._check_recursion, _rec_message, ['parent_id'])] _defaults = { 'sequence': 10, } _order = "morder,id" _parent_store = True
class CompassionChild(models.Model): """ A sponsored child """ _name = 'compassion.child' _rec_name = 'local_id' _inherit = [ 'compassion.generic.child', 'mail.thread', 'translatable.model' ] _description = "Sponsored Child" ########################################################################## # FIELDS # ########################################################################## # General Information ##################### local_id = fields.Char(track_visibility=True) code = fields.Char(help='Old child reference') compass_id = fields.Char('Compass ID', oldname='unique_id') estimated_birthdate = fields.Boolean(readonly=True) cognitive_age_group = fields.Selection([ ('0-2', '0-2'), ('3-5', '3-5'), ('6-8', '6-8'), ('9-11', '9-11'), ('12-14', '12-14'), ('15-18', '15-18'), ('19+', '19+'), ], readonly=True) cdsp_type = fields.Selection([ ('Home based', 'Home based'), ('Center based', 'Center based'), ], track_visibility='onchange', readonly=True) last_review_date = fields.Date(track_visibility='onchange', readonly=True) type = fields.Selection([('CDSP', 'CDSP'), ('LDP', 'LDP')], required=True, default='CDSP') date = fields.Date('Allocation date') completion_date = fields.Date(readonly=True) completion_date_change_reason = fields.Char(readonly=True) state = fields.Selection('_get_child_states', readonly=True, required=True, track_visibility='onchange', default='N') is_available = fields.Boolean(compute='_set_available') sponsor_id = fields.Many2one('res.partner', 'Sponsor', track_visibility='onchange', readonly=True) sponsor_ref = fields.Char('Sponsor reference', related='sponsor_id.ref') has_been_sponsored = fields.Boolean() hold_id = fields.Many2one('compassion.hold', 'Hold', readonly=True) active = fields.Boolean(default=True) exit_reason = fields.Char(compute='_compute_exit_reason') non_latin_name = fields.Char() # Beneficiary Favorites ####################### hobby_ids = fields.Many2many('child.hobby', string='Hobbies', readonly=True) duty_ids = fields.Many2many('child.household.duty', string='Household duties', readonly=True) activity_ids = fields.Many2many('child.project.activity', string='Project activities', readonly=True) subject_ids = fields.Many2many('child.school.subject', string='School subjects', readonly=True) # Education information ####################### education_level = fields.Selection([ ('Not Enrolled', 'Not Enrolled'), ('Preschool', 'Preschool'), ('Primary', 'Primary'), ('Secondary', 'Secondary'), ('University Graduate', 'University Graduate'), ], readonly=True) local_grade_level = fields.Selection([ ('Preschool 1', 'Preschool 1'), ('Preschool 2', 'Preschool 2'), ('Kinder 1', 'Kinder 1'), ('Kinder 2', 'Kinder 2'), ('Kinder 3', 'Kinder 3'), ('Primary 1', 'Primary 1'), ('Primary 2', 'Primary 2'), ('Primary 3', 'Primary 3'), ('Primary 4', 'Primary 4'), ('Primary 5', 'Primary 5'), ('Primary 6', 'Primary 6'), ('Middle 1', 'Middle 1'), ('Middle 2', 'Middle 2'), ('Middle 3', 'Middle 3'), ('High school 1', 'High school 1'), ('High school 2', 'High school 2'), ('High school 3', 'High school 3'), ('Not Enrolled', 'Not Enrolled'), ], readonly=True) us_grade_level = fields.Selection([ ('P', 'P'), ('K', 'K'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8'), ('9', '9'), ('10', '10'), ('11', '11'), ('12', '12'), ('13', '13'), ('14', '14'), ('PK', 'PK'), ], readonly=True) academic_performance = fields.Selection([ ('Above Average', _('above average')), ('Average', _('average')), ('Below Average', _('below average')), ], readonly=True) vocational_training_type = fields.Selection([ ('Agriculture', _('agriculture')), ('Automotive', _('automotive')), ('Business/Administrative', _('business administration')), ('Clothing Trades', _('clothing trades')), ('Computer Technology', _('computer technology')), ('Construction/ Tradesman', _('construction')), ('Cooking / Food Service', _('cooking and food service')), ('Cosmetology', _('cosmetology')), ('Electrical/ Electronics', _('electronics')), ('Graphic Arts', _('graphic arts')), ('Income-Generating Program at Project', 'Income-Generating Program at Project'), ('Manufacturing/ Fabrication', 'Manufacturing/ Fabrication'), ('Medical/ Health Services', 'Medical/ Health Services'), ('Not Enrolled', 'Not Enrolled'), ('Other', 'Other'), ('Telecommunication', _('telecommunication')), ('Transportation', _('transportation')), ('Transportation/ Driver', _('driver')), ], readonly=True) university_year = fields.Selection([ ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ], readonly=True) major_course_study = fields.Selection([ ('Accounting', _('accounting')), ('Agriculture', _('agriculture')), ('Biology / Medicine', _('biology/medicine')), ('Business / Management / Commerce', _('business management')), ('Community Development', _('community development')), ('Computer Science / Information Technology', _('computer science')), ('Criminology / Law Enforcement', _('criminology')), ('Economics', _('economics')), ('Education', _('education')), ('Engineering', _('engineering')), ('English', _('english')), ('Graphic Arts / Fine Arts', _('graphic arts')), ('History', _('history')), ('Hospitality / Hotel Management', _('hospitality / hotel ' 'management')), ('Law', _('law')), ('Mathematics', _('mathematics')), ('Nursing', _('nursing')), ('Other', 'Other'), ('Psychology', _('Psychology')), ('Sales and Marketing', _('sales and marketing')), ('Science', _('science')), ('Sociology / Social Science', _('sociology')), ('Theology', _('theology')), ('Tourism', _('tourism')), ], readonly=True) not_enrolled_reason = fields.Char(readonly=True) # Spiritual information ####################### christian_activity_ids = fields.Many2many('child.christian.activity', string='Christian activities', readonly=True) # Medical information ##################### weight = fields.Char(readonly=True) height = fields.Char(readonly=True) physical_disability_ids = fields.Many2many('child.physical.disability', string='Physical disabilities', readonly=True) chronic_illness_ids = fields.Many2many('child.chronic.illness', string='Chronic illnesses', readonly=True) # Case Studies ############## lifecycle_ids = fields.One2many('compassion.child.ble', 'child_id', 'Lifecycle events', readonly=True) assessment_ids = fields.One2many('compassion.child.cdpr', 'child_id', 'Assessments', readonly=True) note_ids = fields.One2many('compassion.child.note', 'child_id', 'Notes', readonly=True) revised_value_ids = fields.One2many('compassion.major.revision', 'child_id', 'Major revisions', readonly=True) pictures_ids = fields.One2many('compassion.child.pictures', 'child_id', 'Child pictures', track_visibility='onchange', readonly=True) household_id = fields.Many2one('compassion.household', 'Household', readonly=True) portrait = fields.Binary(related='pictures_ids.headshot') fullshot = fields.Binary(related='pictures_ids.fullshot') child_disaster_impact_ids = fields.One2many('child.disaster.impact', 'child_id', 'Child Disaster Impact') # Descriptions ############## desc_en = fields.Text('English description', readonly=True) desc_fr = fields.Text('French description', readonly=True) desc_de = fields.Text('German description', readonly=True) desc_it = fields.Text('Italian description', readonly=True) _sql_constraints = [('compass_id', 'unique(compass_id)', _('The child already exists in database.')), ('global_id', 'unique(global_id)', _('The child already exists in database.'))] ########################################################################## # FIELDS METHODS # ########################################################################## @api.one @api.depends('local_id') def _set_project(self): if self.local_id: project = self.env['compassion.project'].search( [('icp_id', '=', self.local_id[:5])], limit=1) if not project: project = self.env['compassion.project'].create({ 'icp_id': self.local_id[:5], 'name': self.local_id[:5], }) self.project_id = project.id def _get_child_states(self): return [ ('N', _('Consigned')), ('I', _('On Internet')), ('P', _('Sponsored')), ('F', _('Departed')), ('R', _('Released')), ] def _set_available(self): for child in self: child.is_available = child.state in self._available_states() def _available_states(self): return ['N', 'I'] def _compute_exit_reason(self): for child in self: exit_details = child.lifecycle_ids.with_context( lang='en_US').filtered(lambda l: l.type in ('Planned Exit', 'Unplanned Exit')) if exit_details: child.exit_reason = exit_details[0].request_reason ########################################################################## # ORM METHODS # ########################################################################## @api.model def create(self, vals): """ If child with global_id already exists, update it instead of creating a new one. """ global_id = vals.get('global_id') child = self.search([('global_id', '=', global_id)]) if child: child.write(vals) else: child = super(CompassionChild, self).create(vals) return child ########################################################################## # PUBLIC METHODS # ########################################################################## def details_answer(self, vals): """ Called when receiving the answer of GetDetails message. """ self.ensure_one() self.write(vals) self.generate_descriptions() return True @api.model def major_revision(self, commkit_data): """ Called when a MajorRevision Kit is received. """ child_ids = list() child_mapping = CompassionChildMapping(self.env) for child_data in commkit_data.get('BeneficiaryMajorRevisionList', [commkit_data]): global_id = child_data.get('Beneficiary_GlobalID') child = self.search([('global_id', '=', global_id)]) if child: child_ids.append(child.id) child._major_revision( child_mapping.get_vals_from_connect(child_data)) return child_ids ########################################################################## # VIEW CALLBACKS # ########################################################################## @api.multi def get_infos(self): """Get the most recent case study, basic informations, updates portrait picture and creates the project if it doesn't exist. """ message_obj = self.env['gmc.message.pool'] action_id = self.env.ref('child_compassion.beneficiaries_details').id message_vals = { 'action_id': action_id, 'object_id': self.id, 'child_id': self.id, } message_obj.create(message_vals) return True @api.multi def update_child_pictures(self): res = True # Update child's pictures for child in self: res = child._get_last_pictures() and res return res @api.multi def generate_descriptions(self): self.ensure_one() self.desc_fr = ChildDescriptionFr.gen_fr_translation( self.with_context(lang='fr_CH')) self.desc_de = ChildDescriptionDe.gen_de_translation( self.with_context(lang='de_DE')) self.desc_it = ChildDescriptionIt.gen_it_translation( self.with_context(lang='it_IT')) # Lifecycle methods ################### def depart(self): self.signal_workflow('release') def reinstatement(self): """ Called by Lifecycle Event. Hold and state of Child is handled by the Reinstatement Hold Notification. """ self.delete_workflow() self.create_workflow() ########################################################################## # WORKFLOW METHODS # ########################################################################## @api.multi def child_consigned(self): """Called on child allocation.""" self.write({'state': 'N', 'sponsor_id': False}) self.with_context(async_mode=True).get_infos() return True @api.multi def child_sponsored(self): return self.write({'state': 'P', 'has_been_sponsored': True}) @api.multi def child_released(self): """ Is called when a child is released to the global childpool. """ sponsored_children = self.filtered('has_been_sponsored') sponsored_children.write({'sponsor_id': False, 'state': 'R'}) other_children = self - sponsored_children other_children._postpone_deletion() return True @api.multi def child_departed(self): """ Is called when a child is departed. """ sponsored_children = self.filtered('has_been_sponsored') sponsored_children.write({'sponsor_id': False, 'state': 'F'}) other_children = self - sponsored_children other_children._postpone_deletion() return True ########################################################################## # PRIVATE METHODS # ########################################################################## def _postpone_deletion(self): postpone = datetime.now() + timedelta(seconds=10) session = ConnectorSession.from_env(self.env) unlink_children_job.delay(session, self._name, self.ids, eta=postpone) def _get_last_pictures(self): self.ensure_one() pictures_obj = self.env['compassion.child.pictures'] pictures = pictures_obj.create({'child_id': self.id}) if pictures: # Add a note in child self.message_post("The picture has been updated.", "Picture update", 'comment') return pictures def _major_revision(self, vals): """ Private method when a major revision is received for a child. :param vals: Record values received from connect """ self.ensure_one() self.write(vals)
class ResPartnerRelation(models.Model): '''Model res.partner.relation is used to describe all links or relations between partners in the database. In many parts of the code we have to know whether the active partner is the left partner, or the right partner. If the active partner is the right partner we have to show the inverse name. Because the active partner is crucial for the working of partner relationships, we make sure on the res.partner model that the partner id is set in the context where needed. ''' _name = 'res.partner.relation' _description = 'Partner relation' _order = 'active desc, date_start desc, date_end desc' def _search_any_partner_id(self, operator, value): return [ '|', ('left_partner_id', operator, value), ('right_partner_id', operator, value), ] def _get_computed_fields( self, cr, uid, ids, field_names, arg, context=None): '''Return a dictionary of dictionaries, with for every partner for ids, the computed values.''' def get_values(self, dummy_field_names, dummy_arg, context=None): '''Get computed values for record''' values = {} on_right_partner = self._on_right_partner(self.right_partner_id.id) # type_selection_id values['type_selection_id'] = ( ((self.type_id.id) * 10) + (on_right_partner and 1 or 0)) # partner_id_display values['partner_id_display'] = ( self.left_partner_id.id if on_right_partner else self.right_partner_id.id ) return values return dict([ (i.id, get_values(i, field_names, arg, context=context)) for i in self.browse(cr, uid, ids, context=context) ]) _columns = { 'type_selection_id': osv.fields.function( _get_computed_fields, multi="computed_fields", fnct_inv=lambda *args: None, type='many2one', obj='res.partner.relation.type.selection', string='Type', ), 'partner_id_display': osv.fields.function( _get_computed_fields, multi="computed_fields", fnct_inv=lambda *args: None, type='many2one', obj='res.partner', string='Partner' ), } allow_self = fields.Boolean(related='type_id.allow_self') left_contact_type = fields.Selection( lambda s: s.env['res.partner.relation.type']._get_partner_types(), 'Left Partner Type', compute='_get_partner_type_any', store=True, ) right_contact_type = fields.Selection( lambda s: s.env['res.partner.relation.type']._get_partner_types(), 'Right Partner Type', compute='_get_partner_type_any', store=True, ) any_partner_id = fields.Many2many( 'res.partner', string='Partner', compute='_get_partner_type_any', search='_search_any_partner_id' ) left_partner_id = fields.Many2one( 'res.partner', string='Source Partner', required=True, auto_join=True, ondelete='cascade', ) right_partner_id = fields.Many2one( 'res.partner', string='Destination Partner', required=True, auto_join=True, ondelete='cascade', ) type_id = fields.Many2one( 'res.partner.relation.type', string='Type', required=True, auto_join=True, ) date_start = fields.Date('Starting date') date_end = fields.Date('Ending date') active = fields.Boolean('Active', default=True) @api.one @api.depends('left_partner_id', 'right_partner_id') def _get_partner_type_any(self): self.left_contact_type = get_partner_type(self.left_partner_id) self.right_contact_type = get_partner_type(self.right_partner_id) self.any_partner_id = self.left_partner_id + self.right_partner_id def _on_right_partner(self, cr, uid, right_partner_id, context=None): '''Determine wether functions are called in a situation where the active partner is the right partner. Default False! ''' if (context and 'active_ids' in context and right_partner_id in context.get('active_ids', [])): return True return False def _correct_vals(self, vals): """Fill type and left and right partner id, according to whether we have a normal relation type or an inverse relation type """ vals = vals.copy() # If type_selection_id ends in 1, it is a reverse relation type if 'type_selection_id' in vals: prts_model = self.env['res.partner.relation.type.selection'] type_selection_id = vals['type_selection_id'] (type_id, is_reverse) = ( prts_model.browse(type_selection_id). get_type_from_selection_id() ) vals['type_id'] = type_id if self._context.get('active_id'): if is_reverse: vals['right_partner_id'] = self._context['active_id'] else: vals['left_partner_id'] = self._context['active_id'] if vals.get('partner_id_display'): if is_reverse: vals['left_partner_id'] = vals['partner_id_display'] else: vals['right_partner_id'] = vals['partner_id_display'] if vals.get('other_partner_id'): if is_reverse: vals['left_partner_id'] = vals['other_partner_id'] else: vals['right_partner_id'] = vals['other_partner_id'] del vals['other_partner_id'] if vals.get('contact_type'): del vals['contact_type'] return vals @api.multi def write(self, vals): """Override write to correct values, before being stored.""" vals = self._correct_vals(vals) return super(ResPartnerRelation, self).write(vals) @api.model def create(self, vals): """Override create to correct values, before being stored.""" vals = self._correct_vals(vals) return super(ResPartnerRelation, self).create(vals) def on_change_type_selection_id( self, cr, uid, dummy_ids, type_selection_id, context=None): '''Set domain on partner_id_display, when selection a relation type''' result = { 'domain': {'partner_id_display': []}, 'value': {'type_id': False} } if not type_selection_id: return result prts_model = self.pool['res.partner.relation.type.selection'] type_model = self.pool['res.partner.relation.type'] (type_id, is_reverse) = ( prts_model.get_type_from_selection_id( cr, uid, type_selection_id) ) result['value']['type_id'] = type_id type_obj = type_model.browse(cr, uid, type_id, context=context) partner_domain = [] check_contact_type = type_obj.contact_type_right check_partner_category = ( type_obj.partner_category_right and type_obj.partner_category_right.id ) if is_reverse: # partner_id_display is left partner check_contact_type = type_obj.contact_type_left check_partner_category = ( type_obj.partner_category_left and type_obj.partner_category_left.id ) if check_contact_type == 'c': partner_domain.append(('is_company', '=', True)) if check_contact_type == 'p': partner_domain.append(('is_company', '=', False)) if check_partner_category: partner_domain.append( ('category_id', 'child_of', check_partner_category)) result['domain']['partner_id_display'] = partner_domain return result @api.one @api.constrains('date_start', 'date_end') def _check_dates(self): """End date should not be before start date, if not filled :raises exceptions.Warning: When constraint is violated """ if (self.date_start and self.date_end and self.date_start > self.date_end): raise exceptions.Warning( _('The starting date cannot be after the ending date.') ) @api.one @api.constrains('left_partner_id', 'type_id') def _check_partner_type_left(self): """Check left partner for required company or person :raises exceptions.Warning: When constraint is violated """ self._check_partner_type("left") @api.one @api.constrains('right_partner_id', 'type_id') def _check_partner_type_right(self): """Check right partner for required company or person :raises exceptions.Warning: When constraint is violated """ self._check_partner_type("right") @api.one def _check_partner_type(self, side): """Check partner to left or right for required company or person :param str side: left or right :raises exceptions.Warning: When constraint is violated """ assert side in ['left', 'right'] ptype = getattr(self.type_id, "contact_type_%s" % side) company = getattr(self, '%s_partner_id' % side).is_company if (ptype == 'c' and not company) or (ptype == 'p' and company): raise exceptions.Warning( _('The %s partner is not applicable for this relation type.') % side ) @api.one @api.constrains('left_partner_id', 'right_partner_id') def _check_not_with_self(self): """Not allowed to link partner to same partner :raises exceptions.Warning: When constraint is violated """ if self.left_partner_id == self.right_partner_id: if not self.allow_self: raise exceptions.Warning( _('Partners cannot have a relation with themselves.') ) @api.one @api.constrains('left_partner_id', 'right_partner_id', 'active') def _check_relation_uniqueness(self): """Forbid multiple active relations of the same type between the same partners :raises exceptions.Warning: When constraint is violated """ if not self.active: return domain = [ ('type_id', '=', self.type_id.id), ('active', '=', True), ('id', '!=', self.id), ('left_partner_id', '=', self.left_partner_id.id), ('right_partner_id', '=', self.right_partner_id.id), ] if self.date_start: domain += ['|', ('date_end', '=', False), ('date_end', '>=', self.date_start)] if self.date_end: domain += ['|', ('date_start', '=', False), ('date_start', '<=', self.date_end)] if self.search(domain): raise exceptions.Warning( _('There is already a similar relation with overlapping dates') ) def get_action_related_partners(self, cr, uid, ids, context=None): '''return a window action showing a list of partners taking part in the relations names by ids. Context key 'partner_relations_show_side' determines if we show 'left' side, 'right' side or 'all' (default) partners. If active_model is res.partner.relation.all, left=this and right=other''' if context is None: context = {} field_names = {} if context.get('active_model', self._name) == self._name: field_names = { 'left': ['left'], 'right': ['right'], 'all': ['left', 'right'] } elif context.get('active_model') == 'res.partner.relation.all': field_names = { 'left': ['this'], 'right': ['other'], 'all': ['this', 'other'] } else: assert False, 'Unknown active_model!' partner_ids = [] field_names = field_names[ context.get('partner_relations_show_side', 'all')] field_names = ['%s_partner_id' % n for n in field_names] for relation in self.pool[context.get('active_model')].read( cr, uid, ids, context=context, load='_classic_write'): for name in field_names: partner_ids.append(relation[name]) return { 'name': _('Related partners'), 'type': 'ir.actions.act_window', 'res_model': 'res.partner', 'domain': [('id', 'in', partner_ids)], 'views': [(False, 'tree'), (False, 'form')], 'view_type': 'form' }
class PurchaseCreditCardConciliation(models.Model): # Maneja las acciones al cambiar sus estados _name = 'purchase.credit.card.conciliation' @api.depends('fee_ids') def _get_conciliation_total(self): for each in self: each.amount = sum(fee.amount for fee in each.fee_ids) name = fields.Char( 'Nombre', required=True ) date = fields.Date( 'Fecha de conciliación', required=True ) date_from = fields.Date( 'Fecha desde', required=True ) date_to = fields.Date( 'Fecha hasta', required=True ) journal_id = fields.Many2one( 'account.journal', 'Cuenta Bancaria', required=True, ondelete='restrict' ) credit_card_id = fields.Many2one( 'credit.card', 'Tarjeta', required=True, ondelete='restrict' ) amount = fields.Monetary( 'Importe total', compute='_get_conciliation_total', ) currency_id = fields.Many2one( 'res.currency', 'Moneda' ) fee_ids = fields.Many2many( 'purchase.credit.card.fee', 'credit_card_fee_conciliation_rel', 'conciliation_id', 'fee_id', string='Cuotas' ) state = fields.Selection( [('canceled', 'Cancelada'), ('draft', 'Borrador'), ('reconciled', 'Conciliada')], string='Estado', default='draft', ) move_id = fields.Many2one( 'account.move', 'Asiento contable', readonly=True, ondelete='restrict' ) company_id = fields.Many2one( 'res.company', string='Compania', required=True, default=lambda self: self.env.user.company_id, ) _sql_constraints = [('name_uniq', 'unique(name)', 'El nombre de la conciliacion debe ser unico')] _order = "date_from desc, name desc" @api.constrains('date_from', 'date_to') def constraint_dates(self): for conciliation in self: if conciliation.date_from > conciliation.date_to: raise ValidationError("La fecha desde debe ser menor que la fecha hasta.") @api.constrains('fee_ids') def constraint_fees(self): for conciliation in self: if len(conciliation.fee_ids.mapped('currency_id')) > 1: raise ValidationError("Las conciliaciones deben ser de cuotas en la misma moneda.") if len(conciliation.fee_ids.mapped('credit_card_id')) > 1: raise ValidationError("Las conciliaciones deben ser de cuotas de la misma tarjeta.") @api.multi def post(self): for conciliation in self: if not conciliation.fee_ids: raise ValidationError("No se puede validar una conciliación sin cuotas.") conciliation.write({ # Ya validamos en el constraint que la moneda es unica 'currency_id': conciliation.fee_ids.mapped('currency_id').id, 'state': 'reconciled' }) conciliation.move_id = conciliation.create_move() conciliation.fee_ids.reconcile() @api.multi def cancel(self): for conciliation in self: move = conciliation.move_id conciliation.move_id = None move.button_cancel() move.unlink() conciliation.fee_ids.cancel_reconcile() conciliation.state = 'canceled' @api.multi def cancel_to_draft(self): self.write({'state': 'draft'})
class WebsiteSupportTicketUsers(models.Model): _inherit = "res.users" cat_user_ids = fields.Many2many('website.support.ticket.categories', string="Category Users")
class ProjectForecast(models.Model): _inherit = ['project.forecast'] planned_time = fields.Selection([('am', 'AM'), ('pm', 'PM'), ('am_pm', 'AM+PM'), ('specific', 'Specific time')], string='Planned on') issue_ids = fields.Many2many('project.issue', string="Issues", domain="[('project_id', '=', project_id)]") task_ids = fields.Many2many('project.task', string="Tasks", domain="[('project_id', '=', project_id)]") leave_id = fields.Many2one( 'hr.holidays', string="Leave", domain="[('type', '=', 'remove'), ('user_id', '=', user_id)]") project_id = fields.Many2one('project.project', string="Project") comment = fields.Text(string="Comment") tasks_planned_hours = fields.Float(string="Planned time on tasks", compute='_compute_total_planned_hours') @api.multi @api.onchange('task_ids') def _compute_total_planned_hours(self): for forecast in self: forecast.tasks_planned_hours = 0 for task in forecast.task_ids: forecast.tasks_planned_hours += task.planned_hours @api.one @api.onchange('planned_time') def planned_time_changed(self): calendar_ids = self.env['resource.calendar'].search([ ('company_id', '=', self.user_id.company_id.id) ]) worktime = {'morning': 8.5, 'midday': 13.5, 'evening': 17.5} start_date = datetime.strptime(self.start_date, DEFAULT_SERVER_DATETIME_FORMAT) end_date = datetime.strptime(self.end_date, DEFAULT_SERVER_DATETIME_FORMAT) if len(calendar_ids) > 0: for attendance in calendar_ids.attendance_ids: if int(attendance.dayofweek) == start_date.weekday(): worktime['morning'] = attendance.hour_from worktime['midday'] = (attendance.hour_to + attendance.hour_from) / 2 worktime['evening'] = attendance.hour_to break if self.planned_time == 'am': self.start_date = start_date.replace(hour=int(worktime['morning'] - 1)) self.end_date = end_date.replace(hour=int(worktime['midday'] - 1)) elif self.planned_time == 'pm': self.start_date = start_date.replace(hour=int(worktime['midday'] - 1)) self.end_date = end_date.replace(hour=int(worktime['evening'] - 1)) elif self.planned_time == 'am_pm': self.start_date = start_date.replace(hour=int(worktime['morning'] - 1)) self.end_date = start_date.replace(hour=int(worktime['evening'] - 1)) @api.one @api.onchange('leave_id') def leave_changed(self): if self.leave_id: self.start_date = self.leave_id.date_from self.end_date = self.leave_id.date_to
class L10nEsAeatReport(models.AbstractModel): _name = "l10n.es.aeat.report" _description = "AEAT report base module" _rec_name = 'name' _aeat_number = False _period_quarterly = True _period_monthly = True _period_yearly = False def _default_company(self): company_obj = self.env['res.company'] return company_obj._company_default_get('l10n.es.aeat.report') def _default_journal(self): return self.env['account.journal'].search( [('type', '=', 'general')])[:1] def get_period_type_selection(self): period_types = [] if self._period_yearly: period_types += [('0A', '0A - Anual')] if self._period_quarterly: period_types += [('1T', '1T - Primer trimestre'), ('2T', '2T - Segundo trimestre'), ('3T', '3T - Tercer trimestre'), ('4T', '4T - Cuarto trimestre')] if self._period_monthly: period_types += [('01', '01 - Enero'), ('02', '02 - Febrero'), ('03', '03 - Marzo'), ('04', '04 - Abril'), ('05', '05 - Mayo'), ('06', '06 - Junio'), ('07', '07 - Julio'), ('08', '08 - Agosto'), ('09', '09 - Septiembre'), ('10', '10 - Octubre'), ('11', '11 - Noviembre'), ('12', '12 - Diciembre')] return period_types def _default_period_type(self): selection = self.get_period_type_selection() return selection and selection[0][0] or False company_id = fields.Many2one( 'res.company', string='Company', required=True, readonly=True, default=_default_company, states={'draft': [('readonly', False)]}) company_vat = fields.Char( string='VAT number', size=9, required=True, readonly=True, states={'draft': [('readonly', False)]}) number = fields.Char( string='Declaration number', size=13, required=True, readonly=True) previous_number = fields.Char( string='Previous declaration number', size=13, states={'done': [('readonly', True)]}) contact_name = fields.Char( string="Full Name", size=40, help="Must have name and surname.", states={'calculated': [('required', True)], 'confirmed': [('readonly', True)]}) contact_phone = fields.Char( string="Phone", size=9, states={'calculated': [('required', True)], 'confirmed': [('readonly', True)]}) representative_vat = fields.Char( string='L.R. VAT number', size=9, help="Legal Representative VAT number.", states={'confirmed': [('readonly', True)]}) fiscalyear_id = fields.Many2one( 'account.fiscalyear', string='Fiscal year', required=True, readonly=True, states={'draft': [('readonly', False)]}) type = fields.Selection( [('N', 'Normal'), ('C', 'Complementary'), ('S', 'Substitutive')], string='Statement Type', default='N', readonly=True, required=True, states={'draft': [('readonly', False)]}) support_type = fields.Selection( [('C', 'DVD'), ('T', 'Telematics')], string='Support Type', default='T', states={'calculated': [('required', True)], 'done': [('readonly', True)]}) calculation_date = fields.Datetime(string="Calculation date") state = fields.Selection( [('draft', 'Draft'), ('calculated', 'Processed'), ('done', 'Done'), ('posted', 'Posted'), ('cancelled', 'Cancelled')], string='State', readonly=True, default='draft') name = fields.Char(string="Report identifier", size=13, oldname='sequence') model = fields.Many2one( comodel_name="ir.model", compute='_compute_report_model') export_config = fields.Many2one( comodel_name='aeat.model.export.config', string='Export config', domain="[('model', '=', model)]") period_type = fields.Selection( selection="get_period_type_selection", string="Period type", required=True, default=_default_period_type, readonly=True, states={'draft': [('readonly', False)]}) periods = fields.Many2many( comodel_name='account.period', readonly=True, string="Period(s)", states={'draft': [('readonly', False)]}) allow_posting = fields.Boolean(compute="_compute_allow_posting") counterpart_account = fields.Many2one( comodel_name="account.account", help="This account will be the counterpart for all the journal items " "that are regularized when posting the report.") journal_id = fields.Many2one( comodel_name="account.journal", string="Journal", domain=[('type', '=', 'general')], default=_default_journal, help="Journal in which post the move.") move_id = fields.Many2one( comodel_name="account.move", string="Account entry") partner_bank_id = fields.Many2one( comodel_name='res.partner.bank', string='Bank account', help='Company bank account used for the presentation', domain="[('state', '=', 'iban'), ('company_id', '=', company_id)]") _sql_constraints = [ ('name_uniq', 'unique(name)', 'AEAT report identifier must be unique'), ] @api.one def _compute_report_model(self): self.model = self.env['ir.model'].search([('model', '=', self._name)]) @api.one def _compute_allow_posting(self): self.allow_posting = False @api.onchange('company_id') def on_change_company_id(self): """Loads some company data (the VAT number) when the selected company changes. """ if self.company_id.vat: # Remove the ES part from spanish vat numbers # (ES12345678Z => 12345678Z) self.company_vat = re.match( "(ES){0,1}(.*)", self.company_id.vat).groups()[1] self.contact_name = self.env.user.name self.contact_phone = self.env.user.partner_id.phone @api.onchange('period_type', 'fiscalyear_id') def onchange_period_type(self): period_model = self.env['account.period'] if not self.fiscalyear_id: self.periods = False else: fy_date_start = fields.Date.from_string( self.fiscalyear_id.date_start) fy_date_stop = fields.Date.from_string( self.fiscalyear_id.date_stop) if self.period_type == '0A': # Anual if fy_date_start.year != fy_date_stop.year: return { 'warning': {'title': _('Warning'), 'message': _( 'Split fiscal years cannot be automatically ' 'handled. You should select manually the periods.') } } self.periods = self.fiscalyear_id.period_ids.filtered( lambda x: not x.special) elif self.period_type in ('1T', '2T', '3T', '4T'): # Trimestral start_month = (int(self.period_type[:1]) - 1) * 3 + 1 # Para manejar ejercicios fiscales divididos en dos periodos year = (fy_date_start.year if start_month < fy_date_start.month else fy_date_stop.year) period = period_model.find( dt=fields.Date.to_string( datetime(year=year, month=start_month, day=1))) period_date_stop = fields.Date.from_string(period.date_stop) self.periods = period if period_date_stop.month != start_month + 2: # Los periodos no están definidos trimestralmente for i in range(1, 3): month = start_month + i period = period_model.find( dt=fields.Date.to_string( datetime(year=year, month=month, day=1))) self.periods += period elif self.period_type in ('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'): # Mensual month = int(self.period_type) # Para manejar ejercicios fiscales divididos en dos periodos year = (fy_date_start.year if month < fy_date_start.month else fy_date_stop.year) period = period_model.find( dt=fields.Date.to_string( datetime(year=year, month=month, day=1))) period_date_start = fields.Date.from_string(period.date_start) period_date_stop = fields.Date.from_string(period.date_stop) if period_date_start.month != period_date_stop.month: return { 'warning': {'title': _('Warning'), 'message': _( 'It seems that you have defined quarterly periods ' 'or periods in the middle of the month. This ' 'cannot be automatically handled. You should ' 'select manually the periods.') } } self.periods = period @api.model def _report_identifier_get(self, vals): seq_obj = self.env['ir.sequence'] seq_name = "aeat%s-sequence" % self._model._aeat_number company_id = vals.get('company_id', self.env.user.company_id.id) seqs = seq_obj.search([('name', '=', seq_name), ('company_id', '=', company_id)]) return seq_obj.next_by_id(seqs.id) @api.model def create(self, vals): if not vals.get('name'): vals['name'] = self._report_identifier_get(vals) return super(L10nEsAeatReport, self).create(vals) @api.multi def button_calculate(self): res = self.calculate() self.write({'state': 'calculated', 'calculation_date': fields.Datetime.now()}) return res @api.multi def button_recalculate(self): self.write({'calculation_date': fields.Datetime.now()}) return self.calculate() @api.multi def _get_previous_fiscalyear_reports(self, date): """Get the AEAT reports previous to the given date. :param date: Date for looking for previous reports. :return: Recordset of the previous AEAT reports. None if there is no previous reports. """ self.ensure_one() prev_periods = self.fiscalyear_id.period_ids.filtered( lambda x: not x.special and x.date_start < date) prev_reports = None for period in prev_periods: reports = self.search([('periods', '=', period.id)]) if not reports: raise exceptions.Warning( _("There's a missing previous declaration for the period " "%s.") % period.name) if not prev_reports: prev_reports = reports else: prev_reports |= reports return prev_reports @api.multi def calculate(self): for report in self: if not report.periods: raise exceptions.Warning( _('There is no period defined for the report. Please set ' 'at least one period and try again.')) return True @api.multi def button_confirm(self): """Set report status to done.""" self.write({'state': 'done'}) return True @api.multi def _prepare_move_vals(self): self.ensure_one() return { 'date': fields.Date.today(), 'journal_id': self.journal_id.id, 'period_id': self.env['account.period'].find().id, 'ref': self.name, 'company_id': self.company_id.id, } @api.multi def button_post(self): """Create any possible account move and set state to posted.""" self.create_regularization_move() self.write({'state': 'posted'}) return True @api.multi def button_cancel(self): """Set report status to cancelled.""" self.write({'state': 'cancelled'}) return True @api.multi def button_unpost(self): """Remove created account move and set state to done.""" self.mapped('move_id').unlink() self.write({'state': 'cancelled'}) return True @api.multi def button_recover(self): """Set report status to draft and reset calculation date.""" self.write({'state': 'draft', 'calculation_date': None}) return True @api.multi def button_export(self): for report in self: export_obj = self.env[ "l10n.es.aeat.report.%s.export_to_boe" % report.number] export_obj.export_boe_file(report) return True @api.multi def button_open_move(self): self.ensure_one() action = self.env.ref('account.action_move_line_form').read()[0] action['view_mode'] = 'form' action['res_id'] = self.move_id.id del action['view_id'] del action['views'] return action @api.multi def unlink(self): if any(item.state not in ['draft', 'cancelled'] for item in self): raise exceptions.Warning(_("Only reports in 'draft' or " "'cancelled' state can be removed")) return super(L10nEsAeatReport, self).unlink() def init(self, cr): # TODO: Poner en el _register_hook para evitar choque en multi BDs if self._name not in ('l10n.es.aeat.report', 'l10n.es.aeat.report.tax.mapping'): seq_obj = self.pool['ir.sequence'] try: aeat_num = getattr(self, '_aeat_number') if not aeat_num: raise Exception() sequence = "aeat%s-sequence" % aeat_num if not seq_obj.search(cr, SUPERUSER_ID, [('name', '=', sequence)]): seq_vals = {'name': sequence, 'code': 'aeat.sequence.type', 'number_increment': 1, 'implementation': 'no_gap', 'padding': 13 - len(str(aeat_num)), 'number_next_actual': 1, 'prefix': aeat_num } seq_obj.create(cr, SUPERUSER_ID, seq_vals) except: raise exceptions.Warning( "Modelo no válido: %s. Debe declarar una variable " "'_aeat_number'" % self._name)
class IssueInvoiceWizard(models.TransientModel): _name = 'project.issue.invoice.account.wizard' def create_invoice_lines(self, invoice_dict, sales): task_obj = self.pool.get('project.task') invoice_obj = self.env['account.invoice'] sale_line = self.env['sale.order.line'] user = self.env['res.users'].browse(self._uid) invoices_list = [] invoices_list_extra = [] count_lines = 1 first_line_extra = 0 count_lines_extra = 1 limit_lines = user.company_id.maximum_invoice_lines inv = invoice_obj.create(invoice_dict) sales.write({'invoice_ids': [(4, inv.id)]}) invoices_list.append(inv.id) for sale in sales: for line in sale.order_line: if (not line.invoiced) and (line.state not in ('draft', 'cancel')): line_id = line.invoice_line_create() if count_lines <= limit_lines or limit_lines == 0 or limit_lines == -1: inv.write({'invoice_line': [(4, line_id[0])]}) count_lines += 1 else: inv = invoice_obj.create(invoice_dict) sale.write({'invoice_ids': [(4, inv.id)]}) invoices_list.append(inv.id) count_lines = 1 inv.write({'invoice_line': [(4, line_id[0])]}) count_lines += 1 for task in sale.task_ids: if not task.invoice_id: if task.is_closed == False: raise Warning( _('Task pending for close in the sale order %s' % sale.name)) else: account_id = sale.order_line[ 0].product_id.property_account_income.id if not account_id: account_id = sale.order_line[ 0].product_id.categ_id.property_account_income_categ.id if not account_id: prop = self.env['ir.property'].get( 'property_account_income_categ', 'product.category') account_id = prop and prop.id or False invoice_line = { 'name': task.name, 'quantity': 1, 'price_unit': 0, 'discount': sale.project_id.to_invoice.factor, 'account_analytic_id': sale.project_id.id, 'account_id': account_id, 'sequence': 100 } if task.extra == True: if first_line_extra == 0: inv2 = invoice_obj.create(invoice_dict) invoices_list_extra.append(inv2.id) first_line_extra = +1 if count_lines_extra <= limit_lines or limit_lines == 0 or limit_lines == -1: inv2.write( {'invoice_line': [(0, 0, invoice_line)]}) count_lines += 1 else: inv2 = invoice_obj.create(invoice_dict) sales.write({'invoice_ids': [(4, inv2.id)]}) invoices_list_extra.append(inv2.id) count_lines = 1 inv2.write( {'invoice_line': [(0, 0, invoice_line)]}) count_lines += 1 for timesheet in task.timesheet_ids: for account_line in timesheet.line_id: if not account_line.invoice_id: if task.extra == True: account_line.write( {'invoice_id': inv2.id}) else: account_line.write( {'invoice_id': inv.id}) for backorder in task.backorder_ids: if backorder.delivery_note_id and backorder.picking_type_id.code == 'outgoing' and backorder.delivery_note_id.state == 'done' and backorder.invoice_state != 'invoiced' and backorder.state == 'done': backorder.write({'invoice_state': 'invoiced'}) backorder.move_lines.write( {'invoice_state': 'invoiced'}) backorder.delivery_note_id.write( {'state': 'invoiced'}) if task.extra == True: for invoice in invoices_list_extra: backorder.delivery_note_id.write( {'invoice_ids': [(4, invoice)]}) else: for invoice in invoices_list: backorder.delivery_note_id.write( {'invoice_ids': [(4, invoice)]}) for expense_line in task.expense_line_ids: if expense_line.expense_id.state == 'done' or expense_line.expense_id.state == 'paid': for move_lines in expense_line.expense_id.account_move_id.line_id: for lines in move_lines.analytic_lines: if lines.account_id == expense_line.analytic_account and lines.name == expense_line.name and lines.unit_amount == expense_line.unit_quantity and ( lines.amount * -1 / lines.unit_amount ) == expense_line.unit_amount and not lines.invoice_id: if task.extra == True: lines.write( {'invoice_id': inv2.id}) else: lines.write( {'invoice_id': inv.id}) if task.extra == True: task_obj.write(self._cr, self._uid, task.id, {'invoice_id': inv2.id}) else: task_obj.write(self._cr, self._uid, task.id, {'invoice_id': inv.id}) return invoices_list + invoices_list_extra @api.multi def generate_invoice_sale_order(self, sale_orders): result = {} invoice_sale = [] order_obj = self.pool.get('sale.order') for sale in sale_orders: if sale.partner_id and sale.partner_id.property_payment_term.id: pay_term = sale.partner_id.property_payment_term.id else: pay_term = False inv = { 'name': sale.client_order_ref or '', 'origin': sale.name, 'type': 'out_invoice', 'reference': "P%dSO%d" % (sale.partner_id.id, sale.id), 'account_id': sale.partner_id.property_account_receivable.id, 'partner_id': sale.partner_invoice_id.id, 'currency_id': sale.pricelist_id.currency_id.id, 'comment': sale.note, 'payment_term': pay_term, 'fiscal_position': sale.fiscal_position.id or sale.partner_id.property_account_position.id, 'user_id': sale.user_id and sale.user_id.id or False, 'company_id': sale.company_id and sale.company_id.id or False, 'date_invoice': fields.date.today() } invoice_sale += self.create_invoice_lines(inv, sale) sale.write({'state': 'progress'}) return invoice_sale @api.multi def generate_preventive_check(self, contracts): issue_obj = self.env['project.issue'] invoice_obj = self.env['account.invoice'] account_payment_term_obj = self.env['account.payment.term'] currency_obj = self.env['res.currency'] ctx = dict(self._context) invoices_list = [] for contract in contracts: account_id = contract.product_id.property_account_income.id or contract.product_id.categ_id.property_account_income_categ.id if contract.invoice_partner_type == 'branch': for branch in contract.branch_ids: if branch.property_product_pricelist: if contract.pricelist_id.currency_id.id != branch.property_product_pricelist.currency_id.id: import_currency_rate = contract.pricelist_id.currency_id.get_exchange_rate( branch.property_product_pricelist.currency_id, date.strftime(date.today(), "%Y-%m-%d"))[0] else: import_currency_rate = 1 else: if contract.pricelist_id.currency_id.id != contract.company_id.currency_id.id: import_currency_rate = contract.pricelist_id.currency_id.get_exchange_rate( contract.company_id.currency_id, date.strftime(date.today(), "%Y-%m-%d"))[0] else: import_currency_rate = 1 date_due = False if branch.property_payment_term: pterm_list = account_payment_term_obj.compute( branch.property_payment_term.id, value=1, date_ref=time.strftime('%Y-%m-%d')) if pterm_list: pterm_list = [line[0] for line in pterm_list] pterm_list.sort() date_due = pterm_list[-1] invoice = { 'partner_id': branch.id, 'company_id': contract.company_id.id, 'payment_term': branch.property_payment_term.id, 'account_id': branch.property_account_receivable.id, 'name': contract.name, 'currency_id': branch.property_product_pricelist.currency_id.id or contract.company_id.currency_id.id, 'fiscal_position': branch.property_account_position.id, 'date_due': date_due } ctx = dict(self._context) ctx['lang'] = branch.lang ctx['force_company'] = contract.company_id.id ctx['company_id'] = contract.company_id.id self = self.with_context(ctx) inv = invoice_obj.create(invoice) invoices_list.append(inv.id) invoice_line = { 'product_id': contract.product_id.id, 'name': contract.name, 'quantity': 1, 'price_unit': contract.amount_preventive_check * import_currency_rate, 'discount': contract.to_invoice.factor, 'account_analytic_id': contract.id, 'invoice_line_tax_id': [(6, 0, [tax.id for tax in contract.product_id.taxes_id])], 'account_id': account_id } inv.write({'invoice_line': [(0, 0, invoice_line)]}) elif contract.invoice_partner_type == 'customer': date_due = False if contract.partner_id.property_product_pricelist: if contract.pricelist_id.currency_id.id != contract.partner_id.property_product_pricelist.currency_id.id: import_currency_rate = contract.pricelist_id.currency_id.get_exchange_rate( contract.partner_id. property_product_pricelist.currency_id, date.strftime(date.today(), "%Y-%m-%d"))[0] else: import_currency_rate = 1 else: if contract.pricelist_id.currency_id.id != contract.company_id.currency_id.id: import_currency_rate = contract.pricelist_id.currency_id.get_exchange_rate( contract.company_id.currency_id, date.strftime(date.today(), "%Y-%m-%d"))[0] else: import_currency_rate = 1 if contract.partner_id.property_payment_term: pterm_list = account_payment_term_obj.compute( contract.partner_id.property_payment_term.id, value=1, date_ref=time.strftime('%Y-%m-%d')) if pterm_list: pterm_list = [line[0] for line in pterm_list] pterm_list.sort() date_due = pterm_list[-1] invoice = { 'partner_id': contract.partner_id.id, 'company_id': contract.company_id.id, 'payment_term': contract.partner_id.property_payment_term.id, 'account_id': contract.partner_id.property_account_receivable.id, 'name': contract.name, 'currency_id': contract.company_id.currency_id.id, 'fiscal_position': contract.partner_id.property_account_position.id, 'date_due': date_due } ctx = dict(self._context) ctx['lang'] = contract.partner_id.lang ctx['force_company'] = contract.company_id.id ctx['company_id'] = contract.company_id.id self = self.with_context(ctx) inv = invoice_obj.create(invoice) invoices_list.append(inv.id) invoice_line = { 'product_id': contract.product_id.id, 'name': contract.name, 'quantity': 1, 'price_unit': contract.amount_preventive_check * import_currency_rate, 'discount': contract.to_invoice.factor, 'account_analytic_id': contract.id, 'invoice_line_tax_id': [(6, 0, [tax.id for tax in contract.product_id.taxes_id])], 'account_id': account_id } inv.write({'invoice_line': [(0, 0, invoice_line)]}) for issue in issue_obj.search([('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('analytic_account_id', '=', contract.id)]): inv.write({'issue_ids': [(4, issue.id)]}) return invoices_list def get_next_execute_preventive_check(self, contract): next_date_execute = False if contract.preventive_check_invoice_date: if contract.preventive_check_interval_type == 'days': next_date_execute = datetime.strptime( contract.preventive_check_invoice_date, '%Y-%m-%d') + relativedelta( days=+contract.preventive_check_interval_number) elif contract.preventive_check_interval_type == 'weeks': next_date_execute = datetime.strptime( contract.preventive_check_invoice_date, '%Y-%m-%d') + relativedelta( weeks=+contract.preventive_check_interval_number) elif contract.preventive_check_interval_type == 'months': next_date_execute = datetime.strptime( contract.preventive_check_invoice_date, '%Y-%m-%d') + relativedelta( months=+contract.preventive_check_interval_number) else: next_date_execute = False return next_date_execute.date() @api.multi def validate_contracts(self): account_analytic_list = [] partner_ids = [] issue_ids = [] model_ids = [] issue_obj = self.env['project.issue'] contracts = self.env['account.analytic.account'].search([ '|', ('invoice_on_timesheets', '=', True), ('charge_expenses', '=', True), ('id', 'in', self._context.get('active_ids')) ]) if contracts: if self.filter == 'filter_no': issue_ids = issue_obj.search( [ '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ], order='categ_id asc,product_id asc,create_date asc') elif self.filter == 'filter_date': issue_ids = issue_obj.search( [ '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('create_date', '>=', self.date_from), ('create_date', '<=', self.date_to), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ], order='categ_id asc,product_id asc,create_date asc') elif self.filter == 'filter_period': issue_ids = issue_obj.search( [ '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('create_date', '>=', self.period_from.date_start), ('create_date', '<=', self.period_to.date_stop), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ], order='categ_id asc,product_id asc,create_date asc') elif self.filter == 'filter_partner': for partner in self.partner_ids: partner_ids.append(partner.id) issue_ids = issue_obj.search( [ '&', '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), '|', ('partner_id', 'in', partner_ids), ('branch_id', 'in', partner_ids), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ], order='categ_id asc,product_id asc,create_date asc') elif self.filter == 'filter_issue': for issue in self.issue_ids: issue_ids.append(issue.id) issue_ids = issue_obj.search( [ '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('id', 'in', issue_ids), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ], order='categ_id asc,product_id asc,create_date asc') self.issue_invoice_ids = issue_ids else: self.issue_invoice_ids = False self.write({'state': 'done'}) return { 'name': _('Issues to Invoice'), 'type': 'ir.actions.act_window', 'res_model': self._name, 'view_type': 'form', 'view_mode': 'form', 'target': 'new', 'res_id': self.id, 'context': self._context } @api.multi def invoice_contracts(self): wizard_obj = self.env['project.issue.helpdesk.invoice.wizard'] invoices_list_issues = [] issue_list = [] invoice_sale_list = [] invoice_preventive_check_list = [] if self.issue_invoice_ids: for issue in self.issue_invoice_ids: issue_list.append(issue.id) invoices_list_issues = wizard_obj.generate_invoices( self.issue_invoice_ids, issue_list, self.group_customer, self.line_detailed) if self.sale_order_invoice_ids: invoice_sale_list = self.generate_invoice_sale_order( self.sale_order_invoice_ids) if self.contract_preventive_check_ids: invoice_preventive_check_list = self.generate_preventive_check( self.contract_preventive_check_ids) result = self.env['ir.model.data'].get_object_reference( 'account', 'action_invoice_tree1') id = result and result[1] or False act_win = self.env['ir.actions.act_window'].search_read([('id', '=', id)])[0] act_win['domain'] = [ ('id', 'in', invoices_list_issues + invoice_sale_list + invoice_preventive_check_list), ('type', '=', 'out_invoice') ] act_win['name'] = _('Invoices') return act_win @api.one @api.constrains('date_from', 'date_to') def _check_filter_date(self): if self.filter == 'filter_date': if self.date_from > self.date_to: raise Warning(_('Start Date must be less than End Date')) @api.constrains('period_from', 'period_to') def _check_filter_period(self): if self.filter == 'filter_period': if self.period_from.date_start > self.period_to.date_stop: raise Warning(_('Start Period must be less than End Period')) @api.onchange('filter') def get_account_issues(self): contracts = self.env['account.analytic.account'].search([ '|', ('invoice_on_timesheets', '=', True), ('charge_expenses', '=', True), ('id', 'in', self._context.get('active_ids')) ]) if contracts: if self.filter == 'filter_issue': self.init_onchange_call = self.env['project.issue'].search([ '|', '|', ('backorder_ids', '!=', False), ('expense_line_ids', '!=', False), ('timesheet_ids', '!=', False), ('issue_type', '!=', 'preventive check'), ('stage_id.closed', '=', True), ('sale_order_id', '=', False), ('invoice_ids', '=', False), ('analytic_account_id', 'in', self._context.get('active_ids', False)) ]) else: self.issue_ids = False else: self.issue_ids = False @api.onchange('state') def get_account(self): if 'active_ids' in self._context and self._context.get('active_ids'): self.sale_order_invoice_ids = self.env['sale.order'].search([ ('project_id', 'in', self._context.get('active_ids', False)), ('state', '=', 'manual') ]) self.contract_preventive_check_ids = self.env[ 'account.analytic.account'].search([ ('id', 'in', self._context.get('active_ids', False)), ('invoice_preventive_check', '!=', False) ]) line_detailed = fields.Boolean( string="Product lines separate service lines", default=True) group_customer = fields.Boolean(string="Group by customer", default=True) filter = fields.Selection([('filter_no', 'No Filter'), ('filter_date', 'Date'), ('filter_period', 'Period'), ('filter_partner', 'Partner'), ('filter_issue', 'Issue')], string="Filter", required=True, default='filter_no') date_from = fields.Date(string="Start Date") date_to = fields.Date(string="End Date") fiscalyear_id = fields.Many2one('account.fiscalyear', string="Fiscal Year") period_to = fields.Many2one('account.period', string="End Period") period_from = fields.Many2one('account.period', string="Start Period") partner_ids = fields.Many2many('res.partner', string="Customers") init_onchange_call = fields.Many2many('project.issue', compute="get_account_issues", string='Nothing Display', help='field at view init') issue_ids = fields.Many2many( 'project.issue', relation='project_issue_helpdesk_account_wizard_rel', string="Issues") issue_invoice_ids = fields.Many2many( 'project.issue', relation='project_issue_to_invoice_account_wizard_rel', string="Issues") sale_order_invoice_ids = fields.Many2many( 'sale.order', relation='sale_order_to_invoice_account_wizard_rel', string="Sale Orders") state = fields.Selection([('validate', 'Validate'), ('done', 'Done')], string='State') contract_preventive_check_ids = fields.Many2many( 'account.analytic.account', relation='account_analytic_invoice_account_wizard_rel', string="Contracts") _defaults = {'state': 'validate'}
class res_partner(models.Model): _inherit = 'res.partner' @api.model def _sale_communication_method_get(self): return [ ('fax', _('Fax')), ('email', _('Email')), ] # START TO DELETE # @api.model def _sale_invoicing_trigger_get(self): return [ ('picking', _('To the delivery')), ('manual', _('On demand')), ('postpaid', _('On the order')), ] # END TO DELETE # @api.model def _sale_invoiced_on_get(self): return [ ('order', _('Ordered quantities')), ('delivery', _('Delivered quantities')), ] @api.one @api.depends('email', 'fax', 'sale_contact_ids', 'sale_communication_method', 'receipt_demand', 'delay_confirmation') def _compute_sale_communication_value(self): if self.sale_communication_method: self.sale_communication_value = self.env[ 'res.partner'].calcul_value_com(self.sale_contact_ids, self, self.sale_communication_method) else: self.sale_communication_value = '' @api.model def _sale_invoice_postage_get(self): return [ ('never', _('Never')), ('always', _('Always')), ('threshold', _('< Threshold')), ] @api.one def _compute_type_inv_ids(self): partner_type_rcs = self.env['res.partner.type'].search([ ('partner_type_id', '=', self.id) ]) partner_rcs = self.env['res.partner'] if partner_type_rcs: for partner_type in partner_type_rcs: partner_rcs |= partner_type.partner_id self.type_inv_ids = partner_rcs.ids #=========================================================================== # COLUMNS #=========================================================================== # Onglet vente can_order = fields.Boolean(string='Authorized to place an order', default=False) can_be_charged = fields.Boolean(string='Authorized to be charged', default=False) can_be_delivered = fields.Boolean(string='Authorized to be delivered', default=False) can_paid = fields.Boolean(string='Authorized to paid', default=False) type_ids = fields.One2many('res.partner.type', 'partner_id', string='Partners types') type_inv_ids = fields.Many2many('res.partner', 'sale_res_partner_type_partner_rel', 'partner_id', 'partner_type_inv_id', string='Partners types inverse', compute='_compute_type_inv_ids') partial_sale_delivery = fields.Boolean( string='Partial delivery allowed', default=True, help='If you don\'t have enough stock available to ' 'deliver all at once, do you accept partial shipments or not?') generate_sale_rest = fields.Boolean(string='Allowed rest', default=True) receipt_demand = fields.Boolean(string='Acknowledgement or receipt demand', default=False) delay_confirmation = fields.Boolean(string='Delay confirmation', default=False) sale_contact_ids = fields.Many2many( 'res.partner', 'sale_contact_id_partner_rel', 'partner_id', 'contact_id', string='Contacts', help='If you choose a contact, ' 'the communication value will refer to its coordinates') sale_invoicing_method_id = fields.Many2one('account.invoicing.method', string='Invoicing method', required=False, ondelete='restrict') #Champ conservé pour la reprise des données, à supprimer plus tard sale_contact_id = fields.Many2one('res.partner', string='Contact', required=False, ondelete='restrict') sale_communication_method = fields.Selection( '_sale_communication_method_get', string='Communication method') sale_communication_value = fields.Char( string='Communication value', compute='_compute_sale_communication_value') sales_manager_id = fields.Many2one('res.users', string='Sales manager', required=False, ondelete='restrict') seller_id = fields.Many2one('res.users', string='Seller', required=False, ondelete='restrict') stat_family_id = fields.Many2one('partner.stat.family', string='Statistics family', required=False, ondelete='restrict') edi_code = fields.Char(string='EDI code', size=17, required=False) num_with_customer = fields.Char(string='Our number with the customer', size=128, required=False) note_header = fields.Html(string='Note on the sale order header') sale_payment_method_id = fields.Many2one('payment.method', string='Payment method', required=False, ondelete='restrict') # START TO DELETE # sale_invoicing_trigger = fields.Selection( '_sale_invoicing_trigger_get', string='Invoicing trigger method') sale_invoiced_on = fields.Selection( '_sale_invoiced_on_get', string='Invoiced on', help='This field indicates if the invoice on the ' 'basis of quantities actually delivered or on the basis of quantities ordered (can be useful in ' 'case of flat rate, for example)') # END TO DELETE # sale_discount_management = fields.Boolean(string='Discount management', default=False) sale_max_delay = fields.Integer(string='Maximum delay for application', default=0, required=False, help="In days") sale_discount_value = fields.Float(string='Discount value', default=0.0, required=False) #Champ transport sale_incoterm_id = fields.Many2one( 'stock.incoterms', string='Incoterm', required=False, ondelete='restrict', help='Incoterm which ' 'stands for \'International Commercial terms\' implies its a series of sales terms which are used ' 'in the commercial transaction.') sale_invoice_postage = fields.Selection('_sale_invoice_postage_get', string='Invoice postage type') sale_threshold = fields.Float(string='Threshold', default=0.0, required=False) sale_forwarding_agent_id = fields.Many2one('res.partner', string='Forwarding Agent', required=False, ondelete='restrict') sale_delivery_delay = fields.Integer( string='Delivery delay', default=0, required=False, help="Carrier delay (in working days)") sale_delivery_contact_id = fields.Many2one('res.partner', string='Contact', required=False, ondelete='restrict') note_delivery_order = fields.Html(string='Note on delivery order') _sql_constraints = [( 'check_sale_partner_qualified', """CHECK((is_customer=true AND (state='qualified' AND ((can_be_charged = true AND sale_invoicing_method_id IS NOT NULL) OR (can_be_charged=false)) AND ((can_be_delivered = true AND property_account_position_id IS NOT NULL) OR (can_be_delivered=false)) AND ((can_paid = true AND property_payment_term_id IS NOT NULL AND sale_payment_method_id IS NOT NULL) OR (can_paid=false))) OR (state!='qualified')) OR (is_customer=false))""", """Some required fields are not filled, please check the form view of the partner: - if the partner is delivered, you must fill the incoterm and the fiscal position, - if the partner is invoiced, you must fill the invoicing method, - and if the partner can pay, you must fill the payment term and the payment method. """)] # Même contrainte que ci-dessus indenté pour lisibilité. # _sql_constraints = [ # ('check_sale_partner_qualified', # """CHECK(( # is_customer=true AND ( # state='qualified' AND ( # ( # can_be_charged = true AND # sale_invoicing_method_id IS NOT NULL # ) OR (can_be_charged=false) # ) # AND ( # ( # can_be_delivered = true AND # property_account_position_id IS NOT NULL # ) OR (can_be_delivered=false) # ) # AND ( # ( # can_paid = true AND # property_payment_term_id IS NOT NULL AND # sale_payment_method_id IS NOT NULL # ) OR (can_paid=false) # ) # ) OR (state!='qualified') # ) OR (is_customer=false))""", # """Some required fields are not filled, please check the form view of the partner: # - if the partner is delivered, you must fill the incoterm and the fiscal position, # - if the partner is invoiced, you must fill the invoicing method, # - and if the partner can pay, you must fill the payment term and the payment method. # """) # ] @api.onchange('partial_sale_delivery') def _onchange_partial_sale_delivery(self): """ Si 'Livraison incomplète' est décochée, on décoche 'Générer un reliquat' """ if not self.partial_sale_delivery: self.generate_sale_rest = False # # @api.onchange('sale_invoicing_trigger') # def _onchange_sale_invoicing_trigger(self): # """ # Si on passe le mode de déclenchement à la commande, on sélectionne la facturation sur # quantités commandées # Si on passe le mode de déclenchement à la livraison, on sélectionne la facturation sur # quantités livrées # """ # if self.sale_invoicing_trigger in ['manual','postpaid']: # self.sale_invoiced_on = 'order' # elif self.sale_invoicing_trigger == 'picking' and self.property_payment_term_id.payment_type != 'after_invoicing': # self.sale_invoiced_on = 'delivery' # # # @api.onchange('sale_invoiced_on', 'property_payment_term_id') # def _onchange_sale_invoiced_on(self): # """ # On modifie la méthode de déclenchement de facturation en fonction du type de paiement # et du type de facturation (qtés livrées ou commandées) # """ # if self.sale_invoiced_on == 'delivery': # self.sale_invoicing_trigger = 'picking' # elif self.sale_invoiced_on == 'order' and self.property_payment_term_id.payment_type != 'after_invoicing' and self.sale_invoicing_trigger != 'manual': # self.sale_invoicing_trigger = 'postpaid' # @api.one # @api.constrains('sale_invoicing_trigger', 'sale_invoiced_on', 'property_payment_term_id', 'property_payment_term_id.payment_type') # def _check_sale_invoiced_on(self): # """ # Verifie: # - que le déclenchement de la facturation soit cohérent avec le type de facturation # - que la facturation ne se fait pas sur les quantités livrées si la facturation est manuelle # """ # if self.sale_invoiced_on == 'delivery' and self.sale_invoicing_trigger != 'picking': # raise Warning(_('Error ! You cannot have an invoice in the delivered quantities if the invoice trigger is not on the picking')) # # if self.sale_invoiced_on == 'order': # if self.property_payment_term_id.payment_type in ['before_validation', 'before_delivery'] and self.sale_invoicing_trigger not in ['postpaid', 'manual']: # raise Warning(_('Error ! You cannot have an invoice in the ordered quantities if the invoice trigger is not in the order or manual')) @api.one @api.constrains('partial_sale_delivery', 'generate_sale_rest') def _check_partial_sale_delivery(self): """ Verifie que le booléen de génération de reliquat soit bien décoché si celui de livraison incomplète l'es aussi """ if self.is_company and not self.partial_sale_delivery and self.generate_sale_rest: raise Warning( _('Error ! You cannot generate rest if you don\'t accept partial delivery (in the sale tab)' )) return True @api.one @api.constrains('can_order', 'can_be_charged', 'can_be_delivered', 'can_paid') def _check_sale_partner_type(self): """ Dans le cas d'un contact, si celui-ci est lié à une société, la société doit avoir la même configuration que lui (c'est-à-dire qu'elle doit être autorisée à commander si le contact est autorisé à commander, autorisée à payer si le contact l'est etc...). Si le contact n'est pas lié à une société, les 4 booléens doivent être cochés ou aucun ne doit l'être Dans le cas d'une société, si elle est autorisée à commander, on doit avoir au moins un livreur, un facturé et un payeur. """ #Cas d'un contact if not self.is_company: parent_company = self.parent_id #Contact avec société parente if parent_company: if self.can_be_charged and not parent_company.can_be_charged: raise Warning( _('Error ! If the contact can be charged, the parent company' ' must be charged too')) if self.can_be_delivered and not parent_company.can_be_delivered: raise Warning( _('Error ! If the contact can be delivered, the parent company' ' must be delivered too')) if self.can_order and not parent_company.can_order: raise Warning( _('Error ! If the contact can order, the parent company' ' must order too')) if self.can_paid and not parent_company.can_paid: raise Warning( _('Error ! If the contact can pay, the parent company' ' must pay too')) else: #Contact sans société parente bool_count = 0 if self.can_be_charged: bool_count += 1 if self.can_be_delivered: bool_count += 1 if self.can_order: bool_count += 1 if self.can_paid: bool_count += 1 if bool_count != 4 and bool_count != 0: raise Warning( _('Error ! If the contact haven\'t a parent company, it must' ' order, pay, be charged and be delivered, or none of them.' )) else: #Cas d'une société qui peut commander if self.can_order and self.is_customer: delivered = False charged = False paid = False if self.can_be_delivered: delivered = True if self.can_be_charged: charged = True if self.can_paid: paid = True for partner in self.type_ids: if partner.partner_type == 'can_be_delivered': delivered = True elif partner.partner_type == 'can_be_charged': charged = True elif partner.partner_type == 'can_paid': paid = True if not delivered or not charged or not paid: raise Warning( _('Error ! If the partner can order, it must be or have a payer, ' 'a charged and a delivered.')) return True def get_partner_address(self, infos={}, return_id=False): """ Fonction qui ramène toutes les adresses et les clients pour la livraison, la facturation, la commande et le paiement On passe un dictionnaire dans lequel on entre les informations souhaitées. Exemple: Si on ne souhaite que l'adresse de livraison, on entrera uniquement 'delivery' dans le dictionnaire :type self: res.partner :param infos: Dictionnaire contenant les informations souhaitées :type infos: dict :param return_id: True si on veut des ids, False pour des recordset :type return_id: boolean :return: Le dictionnaire contenant les informations demandées :rtype: dict """ res = super(res_partner, self).get_partner_address(infos=infos, return_id=return_id) #La fonction est en deux parties : le cas d'un partenaire client et le cas d'un contact # 1 - Partner client #On vérifie avant tout que le partner soit bien un client, sinon on renvoie un dictionnaire vide partner = self if partner: principal_address = return_id and partner.address_id.id or partner.address_id principal_customer = return_id and partner.id or partner res['order_address'] = principal_address if partner.is_company and partner.is_customer: #On commence par récupérer l'adresse principale du partner pour #la passer en tant qu'adresse de la commande #On regarde ensuite si le partner peut être livré. Si c'est le cas, #on renvoie son adresse principale et l'id du partner if infos.get('delivery'): if partner.can_be_delivered: res['delivery_address'] = principal_address res['delivery_partner'] = principal_customer #Sinon, on recherche et récupère le partner ou contact livré, ainsi que #son adresse principale. else: for line in partner.type_ids: if line.partner_type == 'can_be_delivered': res['delivery_partner'] = return_id and line.partner_type_id.id or line.partner_type_id res['delivery_address'] = return_id and line.partner_type_id.address_id.id or line.partner_type_id.address_id break #On regarde ensuite si le partner peut être facturé. Si c'est le cas, #on renvoie son adresse principale et l'id du partner if infos.get('invoiced'): if partner.can_be_charged: res['invoiced_address'] = principal_address res['invoiced_partner'] = principal_customer #Sinon, on recherche et récupère le partner ou contact facturé, ainsi que #son adresse principale. else: for line in partner.type_ids: if line.partner_type == 'can_be_charged': res['invoiced_partner'] = return_id and line.partner_type_id.id or line.partner_type_id res['invoiced_address'] = return_id and line.partner_type_id.address_id.id or line.partner_type_id.address_id break #On regarde enfin si le partner peut être payeur. Si c'est le cas, #on renvoie id. Sinon, on recherche et récupère le partner ou contact payeur if infos.get('paid'): if partner.can_paid: res['pay_partner'] = principal_customer else: for line in partner.type_ids: if line.partner_type == 'can_paid': res['pay_partner'] = return_id and line.partner_type_id.id or line.partner_type_id break # 2 - Contact elif not partner.is_company: #Si le contact n'est pas lié à un partenaire, on récupère son adresse et son id pour tous les champs if not partner.parent_id and partner.can_be_charged and partner.can_be_delivered and partner.can_paid \ and partner.can_order: if infos.get('delivery'): res['delivery_address'] = principal_address res['delivery_partner'] = principal_customer if infos.get('invoiced'): res['invoiced_address'] = principal_address res['invoiced_partner'] = principal_customer if infos.get('paid'): res['pay_partner'] = principal_customer res['pay_partner'] = principal_customer elif partner.parent_id: related_partner = partner.parent_id if infos.get('invoiced'): if partner.can_be_charged: res['invoiced_address'] = principal_address res['invoiced_partner'] = principal_customer elif related_partner.can_be_charged: res['invoiced_address'] = return_id and related_partner.address_id.id or related_partner.address_id res['invoiced_partner'] = return_id and related_partner.id or related_partner else: for line in related_partner.type_ids: if line.partner_type == 'can_be_charged': res['invoiced_partner'] = return_id and line.partner_type_id.id or line.partner_type_id res['invoiced_address'] = return_id and line.partner_type_id.address_id.id or line.partner_type_id.address_id break if infos.get('delivery'): if partner.can_be_delivered: res['delivery_address'] = principal_address res['delivery_partner'] = principal_customer elif related_partner.can_be_delivered: res['delivery_address'] = related_partner.address_id and related_partner.address_id.id or False res['delivery_partner'] = related_partner.id else: for line in related_partner.type_ids: if line.partner_type == 'can_be_delivered': res['delivery_partner'] = return_id and line.partner_type_id.id or line.partner_type_id res['delivery_address'] = return_id and line.partner_type_id.address_id.id or line.partner_type_id.address_id break if infos.get('paid'): if partner.can_paid: res['pay_partner'] = principal_customer elif related_partner.can_paid: res['pay_partner'] = related_partner.id else: for line in related_partner.type_ids: if line.partner_type == 'can_paid': res['pay_partner'] = return_id and line.partner_type_id.id or line.partner_type_id break return res @api.multi def show_partner_sale(self): """ Fonction qui cherche et retourne les ventes du partenaire """ action_struc = {} action_dict = get_form_view(self, 'sale.action_see_all_sale_order') if action_dict and action_dict.get('id') and action_dict.get('type'): action = self.env[action_dict['type']].browse(action_dict['id']) action_struc = action.read() action_struc[0]['context'] = {'partner_id': self.id} action_struc = action_struc[0] return action_struc def get_sale_transport_fields(self, return_id=False): if self: res = { 'sale_incoterm_id': return_id and self.sale_incoterm_id.id or self.sale_incoterm_id, 'sale_invoice_postage': self.sale_invoice_postage, 'sale_threshold': self.sale_threshold, 'sale_forwarding_agent_id': return_id and self.sale_forwarding_agent_id.id or self.sale_forwarding_agent_id, 'transport_delay': self.sale_delivery_delay, } else: res = { 'sale_incoterm_id': False, 'sale_invoice_postage': False, 'sale_threshold': False, 'sale_forwarding_agent_id': False, 'transport_delay': False, } return res def compute_domain_args(self, args): #Fonction appelée par le search afin de n'afficher que les contacts inscrits dans la liste de contact args2 = [] partner_type_obj = self.env['res.partner.type'] partner_obj = self.env['res.partner'] for arg in args: match = False if isinstance(arg, str) or (isinstance(arg, list) and arg[0] in ('!', '|', '&')): args2.append(arg) continue if arg[0] == 'contact_in_partner_sale': arg[0] = 'id' arg[-1] = [x[1] for x in arg[-1] if x[0] != 2] elif arg[0] == 'partner_contact_sale_order': arg[0] = 'id' arg[1] = 'in' partner_id = arg[-1] arg[-1] = [] for contact in self.browse(partner_id).contact_ids: arg[-1].append(contact.id) elif arg[0] == 'invoiced_customer_in_order_list': arg[0] = 'id' arg[1] = 'in' partner_rs = partner_obj.browse(arg[-1]) if not partner_rs.is_company and partner_rs.parent_id: partner_rs = partner_rs.parent_id arg[-1] = [ x.partner_type_id.id for x in partner_type_obj.search([( 'partner_type', '=', 'can_be_charged'), ('partner_id', '=', partner_rs.id)]) if x.partner_type_id ] elif arg[0] in ('cust_can_order', 'cust_can_be_charged'): if isinstance(arg[-1], list) and arg[-1][0]: arg = ('id', '=', arg[-1][1]) else: match = True args2.append((arg[0][5:], '=', True)) args2.append('|') args2.append(('is_company', '=', False)) args2.append(('is_customer', '=', True)) #On affiche les partenaires qui ont le partenaire passé dans le domaine dans leur liste de facturé elif arg[0] == 'order_customer_in_invoiced_list': arg[0] = 'id' arg[1] = 'in' partner_rs = partner_obj.browse(arg[-1]) if not partner_rs.is_company and partner_rs.parent_id: partner_rs = partner_rs.parent_id arg[-1] = [ x.partner_id.id for x in partner_type_obj.search([('partner_type', '=', 'can_be_charged'), ('partner_type_id', '=', partner_rs.id)]) if x.partner_id ] #On affiche les partenaires livrables qui sont dans la liste du partenaire passé dans le domaine elif arg[0] == 'delivered_customer_in_order_list': arg[0] = 'id' arg[1] = 'in' partner_rs = partner_obj.browse(arg[-1]) if not partner_rs.is_company and partner_rs.parent_id: partner_rs = partner_rs.parent_id arg[-1] = [ x.partner_type_id.id for x in partner_type_obj.search([( 'partner_type', '=', 'can_be_delivered'), ('partner_id', '=', partner_rs.id)]) if x.partner_type_id ] #On affiche les partenaires payeurs qui sont dans la liste du partenaire passé dans le domaine elif arg[0] == 'paid_customer_in_order_list': arg[0] = 'id' arg[1] = 'in' partner_rs = partner_obj.browse(arg[-1]) if not partner_rs.is_company and partner_rs.parent_id: partner_rs = partner_rs.parent_id arg[-1] = [ x.partner_type_id.id for x in partner_type_obj.search([( 'partner_type', '=', 'can_paid'), ('partner_id', '=', partner_rs.id)]) if x.partner_type_id ] if not match: args2.append(arg) return args2 @api.model def search(self, args=None, offset=0, limit=None, order=None, count=None): #Modification du search afin de n'afficher que les contacts inscrits dans la liste de contact args = args or [] args_modified = self.compute_domain_args(args) return super(res_partner, self).search(args=args_modified, offset=offset, limit=limit, order=order, count=count) @api.model def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): domain = self.compute_domain_args(domain) return super(res_partner, self).read_group(domain=domain, fields=fields, groupby=groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) def modif_value_partner_type(self, modif_field): """" Mise à jour des champs dans les partenaires, selon les informations rentrées dans res.partner.type :param modif_field: Liste pour savoir quoi modifier: can_be_delivered, can_be_charged, can_paid, type_ids :type modif_field: char """ res = super(res_partner, self).modif_value_partner_type(modif_field=modif_field) if modif_field == 'can_paid' and self.can_paid: request = """Select partner_type_val.partner_id From (Select partner_id, id From res_partner_type Where partner_type_id = %s and partner_type = 'can_paid') partner_type_val, res_partner Where (res_partner.can_paid is null or res_partner.can_paid = false) and partner_type_val.partner_id = res_partner.id and partner_type_val.id = (Select id From res_partner_type Where partner_type = 'can_paid' and partner_id = partner_type_val.partner_id order by sequence asc limit 1) """ % ( self.id) self.env.cr.execute(request) res_sql = self.env.cr.fetchall() if res_sql: partner_ids = [x[0] for x in res_sql] paid_vals = {} for x in self.paid_fields_partner(): if type(self[x]) is not int and type( self[x] ) is not str and type(self[x]) is not float and type( self[x]) is not bool and type( self[x]) is not unicode and self[x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): paid_vals[x] = [] for i in self[x].ids: paid_vals[x].append((4, i)) else: paid_vals[x] = self[x].id else: paid_vals[x] = self[x] self.browse(partner_ids).write(paid_vals) elif modif_field == 'can_be_delivered' and self.can_be_delivered: request = """Select partner_type_val.partner_id From (Select partner_id, id From res_partner_type Where partner_type_id = %s and partner_type = 'can_be_delivered') partner_type_val, res_partner Where (res_partner.can_be_delivered is null or res_partner.can_be_delivered = false) and partner_type_val.partner_id = res_partner.id and partner_type_val.id = (Select id From res_partner_type Where partner_type = 'can_be_delivered' and partner_id = partner_type_val.partner_id order by sequence asc limit 1) """ % ( self.id) self.env.cr.execute(request) res_sql = self.env.cr.fetchall() if res_sql: partner_ids = [x[0] for x in res_sql] delivered_vals = {} for x in self.delivered_fields_partner(): if type(self[x]) is not int and type( self[x] ) is not str and type(self[x]) is not float and type( self[x]) is not bool and type( self[x]) is not unicode and self[x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): delivered_vals[x] = [] for i in self[x].ids: delivered_vals[x].append((4, i)) else: delivered_vals[x] = self[x].id else: delivered_vals[x] = self[x] self.browse(partner_ids).write(delivered_vals) elif modif_field == 'can_be_charged' and self.can_be_charged: request = """Select partner_type_val.partner_id From (Select partner_id, id From res_partner_type Where partner_type_id = %s and partner_type = 'can_be_charged') partner_type_val, res_partner Where (res_partner.can_be_charged is null or res_partner.can_be_charged = false) and partner_type_val.partner_id = res_partner.id and partner_type_val.id = (Select id From res_partner_type Where partner_type = 'can_be_charged' and partner_id = partner_type_val.partner_id order by sequence asc limit 1) """ % ( self.id) self.env.cr.execute(request) res_sql = self.env.cr.fetchall() if res_sql: partner_ids = [x[0] for x in res_sql] invoiced_vals = {} for x in self.invoiced_fields_partner(): if type(self[x]) is not int and type( self[x] ) is not str and type(self[x]) is not float and type( self[x]) is not bool and type( self[x]) is not unicode and self[x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): invoiced_vals[x] = [] for i in self[x].ids: invoiced_vals[x].append((4, i)) else: invoiced_vals[x] = self[x].id else: invoiced_vals[x] = self[x] self.browse(partner_ids).write(invoiced_vals) elif modif_field == 'type_ids': partner_type_obj = self.env['res.partner.type'] if not self.can_paid: partner_type_rcs = partner_type_obj.search( [('partner_type', '=', 'can_paid'), ('partner_id', '=', self.id)], order='sequence asc', limit=1) if partner_type_rcs: paid_vals = {} for x in self.paid_fields_partner(): if type( partner_type_rcs.partner_type_id[x] ) is not int and type( partner_type_rcs.partner_type_id[x] ) is not str and type( partner_type_rcs.partner_type_id[x] ) is not float and type( partner_type_rcs.partner_type_id[x] ) is not bool and type( partner_type_rcs.partner_type_id[x] ) is not unicode and partner_type_rcs.partner_type_id[ x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): paid_vals[x] = [] for i in partner_type_rcs.partner_type_id[ x].ids: paid_vals[x].append((4, i)) else: paid_vals[ x] = partner_type_rcs.partner_type_id[x].id else: paid_vals[x] = partner_type_rcs.partner_type_id[x] self.write(paid_vals) if not self.can_be_delivered: partner_type_rcs = partner_type_obj.search( [('partner_type', '=', 'can_be_delivered'), ('partner_id', '=', self.id)], order='sequence asc', limit=1) if partner_type_rcs: delivered_vals = {} for x in self.delivered_fields_partner(): if type( partner_type_rcs.partner_type_id[x] ) is not int and type( partner_type_rcs.partner_type_id[x] ) is not str and type( partner_type_rcs.partner_type_id[x] ) is not float and type( partner_type_rcs.partner_type_id[x] ) is not bool and type( partner_type_rcs.partner_type_id[x] ) is not unicode and partner_type_rcs.partner_type_id[ x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): delivered_vals[x] = [] for i in partner_type_rcs.partner_type_id[ x].ids: delivered_vals[x].append((4, i)) else: delivered_vals[ x] = partner_type_rcs.partner_type_id[x].id else: delivered_vals[ x] = partner_type_rcs.partner_type_id[x] self.write(delivered_vals) if not self.can_be_charged: partner_type_rcs = partner_type_obj.search( [('partner_type', '=', 'can_be_charged'), ('partner_id', '=', self.id)], order='sequence asc', limit=1) if partner_type_rcs: invoiced_vals = {} for x in self.invoiced_fields_partner(): if type( partner_type_rcs.partner_type_id[x] ) is not int and type( partner_type_rcs.partner_type_id[x] ) is not str and type( partner_type_rcs.partner_type_id[x] ) is not float and type( partner_type_rcs.partner_type_id[x] ) is not bool and type( partner_type_rcs.partner_type_id[x] ) is not unicode and partner_type_rcs.partner_type_id[ x] != None: if isinstance( (self._fields[x]), fields.Many2many) or isinstance( (self._fields[x]), fields.One2many): invoiced_vals[x] = [] for i in partner_type_rcs.partner_type_id[ x].ids: invoiced_vals[x].append((4, i)) else: invoiced_vals[ x] = partner_type_rcs.partner_type_id[x].id else: invoiced_vals[ x] = partner_type_rcs.partner_type_id[x] self.write(invoiced_vals) return res
class grpCajaChicaAccountVoucherWizard(models.TransientModel): _name = "grp.caja.chica.account.voucher.wizard" @api.model def fields_view_get(self, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): res = super(grpCajaChicaAccountVoucherWizard, self).fields_view_get(view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) doc = etree.XML(res['arch']) if self._context is not None and 'default_caja_chica_id' in self._context: caja_id = self._context['default_caja_chica_id'] caja = self.env['grp.caja.chica.tesoreria'].search([('id', '=', caja_id)]) account_vouchers = self.env['account.voucher'].search([ ('state', '=', 'confirm'), ('id', 'not in', caja.transaction_ids.mapped('voucher_id').ids), ('journal_id.caja_chica_t', '=', True), ('journal_id.operating_unit_id', 'in', caja.box_id.operating_unit_ids.ids) ]) if self.env.user.company_id.box_refund_in_selection == 'out_box': account_vouchers += self.env['account.voucher'].search([ ('state', '=', 'posted'), ('id', 'not in', caja.transaction_ids.mapped('voucher_id').ids), ('journal_id.type', '=', 'sale'), ('operating_unit_id', 'in', caja.box_id.operating_unit_ids.ids), '|', ('rendicion_viaticos_id', '!=', False), ('rendicion_anticipos_id', '!=', False) ]) for field in res['fields']: if field == 'account_voucher_ids': res['fields'][field]['domain'] = [ ('id', 'in', account_vouchers.filtered(lambda x: x.currency_id.id == caja.currency.id).ids) ] res['arch'] = etree.tostring(doc) return res payment_date = fields.Date('Fecha de pago', default=lambda *a: fields.Date.today(), required=True) entry_date = fields.Date('Fecha de asiento', default=lambda *a: fields.Date.today(), required=True) account_voucher_ids = fields.Many2many('account.voucher', string=u'Pago a proveedores') caja_chica_id = fields.Many2one('grp.caja.chica.tesoreria', string='Caja chica', ondelete='cascade') @api.onchange('payment_date') def _onchange_payment_date(self): self.entry_date = self.payment_date @api.multi def transfer_account_voucher(self): self.ensure_one() vouchers = self.mapped('account_voucher_ids') vouchers.write({ 'date': self.payment_date, 'entry_date': self.entry_date }) out_voucher_ids = vouchers.filtered( lambda x: not x.rendicion_viaticos_id and not x. rendicion_anticipos_id) in_voucher_ids = vouchers.filtered( lambda x: x.rendicion_viaticos_id or x.rendicion_anticipos_id) # out_voucher_ids.write({'date': self.payment_date, 'entry_date': self.entry_date}) vouchers.with_context({'in_cashbox': True}).proforma_voucher() in_voucher_ids.write({'in_cashbox': True, 'state': 'pagado'}) new_trasactions = [(0, 0, { 'voucher_id': voucher.id, 'ref': self.is_vale_viatico(voucher), 'account_move_id': voucher.move_id.id, 'date': self.payment_date, 'entry_date': self.entry_date, 'partner_id': voucher.partner_id.id, 'amount': voucher.amount * -1 }) for voucher in out_voucher_ids] new_trasactions.extend([(0, 0, { 'voucher_id': voucher.id, 'ref': self.is_vale_viatico(voucher), 'account_move_id': voucher.move_id.id, 'date': self.payment_date, 'entry_date': self.entry_date, 'partner_id': voucher.partner_id.id, 'amount': voucher.amount }) for voucher in in_voucher_ids]) self.caja_chica_id.write({'transaction_ids': new_trasactions}) return True # TODO: C SPRING 12 GAP_301 # RAGU: Seteando valores de ref para las lineas de la caja chica def is_vale_viatico(self, voucher): _vale_rec_name = False if voucher.rendicion_viaticos_id: _vale_rec_name = u'%s' % ( voucher.rendicion_viaticos_id.name_get()[0][1]) elif voucher.solicitud_viatico_id: _vale_rec_name = u'%s' % ( voucher.solicitud_viatico_id.name_get()[0][1]) elif voucher.rendicion_anticipos_id: _vale_rec_name = u'%s' % ( voucher.rendicion_anticipos_id.name_get()[0][1]) elif voucher.solicitud_anticipos_id: _vale_rec_name = u'%s' % ( voucher.solicitud_anticipos_id.name_get()[0][1]) if not _vale_rec_name: vale = self.env['grp.vale.caja'].search([ ('aprobacion_pago_id', '=', voucher.invoice_id.id) ]) if voucher.invoice_id else False if vale: vale.write({'state': 'pagado'}) _vale_rec_name = u'Vale(%s)' % (vale.number) s = set() for line_dr_id in voucher.line_dr_ids.filtered( lambda x: x.reconcile): if line_dr_id.move_line_id.invoice.supplier_invoice_number: s.add(line_dr_id.move_line_id.invoice. supplier_invoice_number) s = list(s) if s: _vale_rec_name = u'Factura(%s)' % (', '.join(s)) if not _vale_rec_name: _vale_rec_name = voucher.nro_documento and voucher.nro_documento.find( ', ') == -1 and voucher.nro_documento or voucher.number return _vale_rec_name
class Currency_rate_update_service(models.Model): """Class keep services and currencies that have to be updated""" _name = "currency.rate.update.service" _description = "Currency Rate Update" @api.one @api.constrains('max_delta_days') def _check_max_delta_days(self): if self.max_delta_days < 0: raise exceptions.Warning(_('Max delta days must be >= 0')) @api.one @api.constrains('interval_number') def _check_interval_number(self): if self.interval_number < 0: raise exceptions.Warning(_('Interval number must be >= 0')) @api.onchange('interval_number') def _onchange_interval_number(self): if self.interval_number == 0: self.note = '%s Service deactivated. Currencies will no longer ' \ 'be updated. \n%s' % (fields.Datetime.now(), self.note and self.note or '') @api.onchange('service') def _onchange_service(self): currency_list = '' if self.service: currencies = [] currency_list = supported_currency_array company_id = False if self.company_id.multi_company_currency_enable: company_id = self.company_id.id currency_list = supported_currecies[self.service] if company_id: currencies = self.env['res.currency'].search([ ('name', 'in', currency_list), '|', ('company_id', '=', company_id), ('company_id', '=', False) ]) else: currencies = self.env['res.currency'].search([ ('name', 'in', currency_list), ('company_id', '=', False) ]) self.currency_list = [(6, 0, [curr.id for curr in currencies])] # _logger.info("Self currency list %s:" % self.currency_list) # _logger.info("Company currency list %s:" % currencies) # List of webservicies the value sould be a class name service = fields.Selection( [ ('CH_ADMIN_getter', 'Admin.ch'), ('ECB_getter', 'European Central Bank'), ('YAHOO_getter', 'Yahoo Finance'), # Added for polish rates ('PL_NBP_getter', 'National Bank of Poland'), # Added for mexican rates ('MX_BdM_getter', 'Bank of Mexico'), # Bank of Canada is using RSS-CB # http://www.cbwiki.net/wiki/index.php/Specification_1.1 # This RSS format is used by other national banks # (Thailand, Malaysia, Mexico...) ('CA_BOC_getter', 'Bank of Canada - noon rates'), # Added for romanian rates ('RO_BNR_getter', 'National Bank of Romania'), # Added for bulgarian rates of central, statiscs (customs) and buy and sell from two bank ('BG_CUSTOMS_getter', 'Bulgarian customs rate for taxes'), ('BG_SIBANK_getter', 'bulgarian SiBank bay and sell currency rates'), ('BG_UNICRDT_getter', 'bulgarian Unicredit Bulbank bay and sell currency rates'), ], string="Webservice to use", required=True) # List of currencies available on webservice currency_list = fields.Many2many('res.currency', 'res_currency_update_avail_rel', 'service_id', 'currency_id', string='Currencies available') # List of currency to update currency_to_update = fields.Many2many('res.currency', 'res_currency_auto_update_rel', 'service_id', 'currency_id', string='Currencies to update with ' 'this service') # Link with company company_id = fields.Many2one( 'res.company', 'Company', default=lambda self: self.env['res.company']._company_default_get( 'currency.rate.update.service')) # Note fileds that will be used as a logger note = fields.Text('Update logs') max_delta_days = fields.Integer( string='Max delta days', default=4, required=True, help="If the time delta between the rate date given by the " "webservice and the current date exceeds this value, " "then the currency rate is not updated in OpenERP.") interval_type = fields.Selection([('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')], string='Currency update frequency', default='days') interval_number = fields.Integer(string='Frequency', default=1) next_run = fields.Date(string='Next run on', default=fields.Date.today()) _sql_constraints = [('curr_service_unique', 'unique (service, company_id)', _('You can use a service only one time per ' 'company !'))] @api.one def refresh_currency(self): """Refresh the currencies rates !!for all companies now""" _logger.info( 'Starting to refresh currencies with service %s (company: %s)', self.service, self.company_id.name) factory = Currency_getter_factory() _logger.info("Factory %s:" % factory) curr_obj = self.env['res.currency'] rate_obj = self.env['res.currency.rate'] company = self.company_id # The multi company currency can be set or no so we handle # The two case if company.auto_currency_up: main_currency = curr_obj.search([('base', '=', True), ('company_id', '=', company.id)], limit=1) if not main_currency: # If we can not find a base currency for this company # we look for one with no company set main_currency = curr_obj.search([('base', '=', True), ('company_id', '=', False)], limit=1) if not main_currency: raise exceptions.Warning(_('There is no base currency set!')) if main_currency.rate != 1: raise exceptions.Warning( _('Base currency rate should ' 'be 1.00!')) note = self.note or '' try: # We initalize the class that will handle the request # and return a dict of rate getter = factory.register(self.service) #self.init_updated_currency() _logger.info("Execute %s: -> %s" % (getter, self.currency_to_update)) curr_to_fetch = map(lambda x: x.name, self.currency_to_update) res, log_info = getter.get_updated_currency( curr_to_fetch, main_currency.name, self.max_delta_days) rate_name = \ fields.Datetime.to_string(datetime.utcnow().replace( hour=0, minute=0, second=0, microsecond=0)) for curr in self.currency_to_update: if curr.id == main_currency.id: continue do_create = True # _logger.info("res curr %s" % res) for rate in curr.rate_ids: _logger.info( "to update: %s:%s from date: %s to date: %s->%s" % (curr.id, rate['currency_id'], rate_name, rate.name, rate)) if rate.name == rate_name and rate.currency_id == curr.id: vals = { 'rate': res['rate'] and res['rate'][curr.name] or 0, 'rate_buy': res['rate_buy'] and res['rate_buy'][curr.name] or 0, 'rate_sell': res['rate_sell'] and res['rate_sell'][curr.name] or 0, 'rate_statistics': res['rate_statistics'] and res['rate_statistics'][curr.name] or 0, } rate_obj.write(vals) _logger.info( 'Updated currency %s via service %s on date %s', curr.name, self.service, rate_name) do_create = False break else: vals = { 'currency_id': curr.id, 'rate': res['rate'] and res['rate'][curr.name] or 0, 'rate_buy': res['rate_buy'] and res['rate_buy'][curr.name] or 0, 'rate_sell': res['rate_sell'] and res['rate_sell'][curr.name] or 0, 'rate_statistics': res['rate_statistics'] and res['rate_statistics'][curr.name] or 0, 'name': rate_name } do_create = True break if do_create: rate_obj.create(vals) _logger.info( 'Updated add currency %s via service %s on date %s', curr.name, self.service, rate_name) # Show the most recent note at the top msg = '%s \n%s currency updated. %s' % ( log_info or '', fields.Datetime.to_string( datetime.today()), note) self.write({'note': msg}) except Exception as exc: error_msg = '\n%s ERROR : %s %s' % (fields.Datetime.to_string( datetime.today()), repr(exc), note) _logger.error(repr(exc)) self.write({'note': error_msg}) if self._context.get('cron', False): midnight = time(0, 0) next_run = (datetime.combine( fields.Date.from_string(self.next_run), midnight) + _intervalTypes[str(self.interval_type)]( self.interval_number)).date() self.next_run = next_run @api.multi def run_currency_update(self): # Update currency at the given frequence # _logger.info('Check for refresh %s' % fields.Date.today()) services = self.search([('next_run', '<=', fields.Date.today())]) services.with_context(cron=True).refresh_currency() @api.model def _run_currency_update(self): _logger.info('Starting the currency rate update cron') self.run_currency_update() _logger.info('End of the currency rate update cron')
class Session(models.Model): _name = 'openacademy.session' name = fields.Char(required=True) start_date = fields.Date(default=fields.Date.today) duration = fields.Float(digits=(6, 2), help="Duration in days") seats = fields.Integer(string="Number of seats") active = fields.Boolean(default=True) instructor_id = fields.Many2one('res.partner', string="Instructor", domain=['|', ('instructor', '=', True), ('category_id.name', 'ilike', "Teacher")]) course_id = fields.Many2one('openacademy.course', ondelete='cascade', string="Course", required=True) attendee_ids = fields.Many2many('res.partner', string="Attendees") taken_seats = fields.Float(string="Taken seats", compute='_taken_seats') end_date = fields.Date(store=True, compute='_get_end_date', inverse='_set_end_date') hours = fields.Float(string="Duration in hours", compute='_get_hours', inverse='_set_hours') attendees_count = fields.Integer(compute='_get_attendees_count', store=True) color = fields.Integer() state = fields.Selection([ ('draft', "Draft"), ('confirmed', "Confirmed"), ('done', "Done"), ]) @api.multi def action_draft(self): self.state = 'draft' @api.multi def action_confirm(self): self.state = 'confirmed' @api.multi def action_done(self): self.state = 'done' @api.depends('attendee_ids') def _get_attendees_count(self): for r in self: r.attendees_count = len(r.attendee_ids) @api.depends('duration') def _get_hours(self): for r in self: r.hours = r.duration * 24 def _set_hours(self): for r in self: r.duration = r.hours / 24 @api.depends('start_date', 'duration') def _get_end_date(self): for r in self: if not (r.start_date and r.duration): r.end_date = r.start_date continue start = fields.Datetime.from_string(r.start_date) duration = timedelta(days=r.duration, seconds=-1) r.end_date = start + duration def _set_end_date(self): for r in self: if not (r.start_date and r.end_date): continue start_date = fields.Datetime.from_string(r.start_date) end_date = fields.Datetime.from_string(r.end_date) r.duration = (end_date - start_date).days + 1 @api.depends('seats', 'attendee_ids') def _taken_seats(self): for r in self: if not r.seats: r.taken_seats = 0.0 else: r.taken_seats = 100.0 * len(r.attendee_ids) / r.seats @api.onchange('seats', 'attendee_ids') def _verify_valid_seats(self): if self.seats < 0: return { 'warning': { 'title': "Incorrect 'seats' value", 'message': "The number of available seats may not be negative", }, } if self.seats < len(self.attendee_ids): return { 'warning': { 'title': "Too many attendees", 'message': "Increase seats or remove excess attendees", }, } @api.constrains('instructor_id', 'attendee_ids') def _check_instructor_not_in_attendees(self): for r in self: if r.instructor_id and r.instructor_id in r.attendee_ids: raise exceptions.ValidationError("A session's instructor can't be an attendee")
class advance_rm_material(models.Model): _name = 'advance.rm.material' _description = "Advance Raw Material Plan" _inherit = ['mail.thread', 'ir.needaction_mixin'] _order = 'create_date desc' @api.multi def button_dummy(self): return True @api.multi def generate_po(self): # supplier_dict = {} product_list = [] po_ids = [] po_raise_list = [] supplier_name = False for record in self.advance_rawmaterial_one2many: if record.po_raise == True: po_raise_list.append(record) if po_raise_list: supplier_dict = {} for po in po_raise_list: product_product = self.env['product.product'].search([ ('product_tmpl_id', '=', po.product_id.id) ]) if po.supplier_id.id in supplier_dict: supplier_dict[po.supplier_id.id].append( (product_product, po.po_qty, po.current_price)) else: supplier_dict[po.supplier_id.id] = [ (product_product, po.po_qty, po.current_price) ] else: # print "Hai hi nahi koi PO raise" raise UserError('No PO raise is found ') for supplier_name, product_name in supplier_dict.iteritems(): if supplier_name: vals = { 'partner_id': supplier_name, 'type_order': 'purchase', 'date_order': self.date, # 'date_planned':self.date, # 'currency_id':'INR' 'advance_rm_material_id': self.id, 'origin': self.fg_plan.name + " / " + self.name } purchase_order = self.env['purchase.order'].create(vals) po_ids.append(purchase_order.id) for products in product_name: vals_line = { 'product_id': products[0].id, # 'tax_id':[(4,products[0].supplier_taxes_id.id)], 'taxes_id': [(4, x.id) for x in products[0].supplier_taxes_id], 'date_planned': self.date, 'order_id': purchase_order.id, 'product_qty': products[1], 'name': products[0].name, 'product_uom': products[0].uom_po_id.id, 'price_unit': products[2] if (products[2] > 0) else products[0].standard_price, } self.env['purchase.order.line'].create(vals_line) else: raise UserError('Please Select Supplier For all the Products') imd = self.env['ir.model.data'] action = self.env.ref('purchase.purchase_rfq') result = action.read([])[0] result['domain'] = [('id', 'in', po_ids)] self.state = 'done' # print Error return result @api.multi def count_docs(self): po_ids = self.env['purchase.order'].search([("advance_rm_material_id", "=", self.id)]) if len(po_ids): self.attach_doc_count = len(po_ids) or 0 @api.multi def get_attached_docs(self): po_ids = self.env['purchase.order'].search([("advance_rm_material_id", "=", self.id)]) imd = self.env['ir.model.data'] action = imd.xmlid_to_object('purchase.purchase_rfq') list_view_id = imd.xmlid_to_res_id('purchase.purchase_order_tree') form_view_id = imd.xmlid_to_res_id('purchase.purchase_order_form') result = { 'name': action.name, 'help': action.help, 'type': action.type, 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], [False, 'calendar'], [False, 'pivot']], 'target': action.target, 'context': action.context, 'res_model': action.res_model, } if len(po_ids) > 1: result['domain'] = "[('id','in',%s)]" % po_ids.ids elif len(po_ids) == 1: result['views'] = [(form_view_id, 'form')] result['res_id'] = po_ids.ids[0] else: result = {'type': 'ir.actions.act_window_close'} return result name = fields.Char(string="Plan No.", track_visibility='always') fg_plan = fields.Many2one('advance.fg.material', string='FG Plan No.') date = fields.Date(string="Date") user_id = fields.Many2one('res.users', string='User', default=lambda self: self._uid, track_visibility='always') advance_rawmaterial_one2many = fields.One2many( 'advance.rawmaterial', 'advance_rm_material_id', string="Advance Raw Material") # purchase_order_id = fields.Many2one('purchase.order', track_visibility='always' ) purchase_order_ids = fields.Many2many("purchase.order", string='Purchases', compute="get_attached_docs", readonly=True, copy=False) attach_doc_count = fields.Integer(string="Number of documents attached", compute='count_docs') average_forecast = fields.Integer(string="Average Forecast", required=True) months = fields.Selection([ ('three', 'Three'), ('six', 'Six'), ('year', 'Year'), ], string='Months', track_visibility='always', default='three') state = fields.Selection([ ('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancelled'), ], string='Status', readonly=True, copy=False, index=True, track_visibility='always', default='draft') @api.model def create(self, vals): vals['name'] = self.env['ir.sequence'].next_by_code( 'advance.rm.material') # vals['state'] = 'done' result = super(advance_rm_material, self).create(vals) if result.fg_plan: result.fg_plan.state = result.state result.fg_plan.advance_rm_material_id = result.id return result @api.multi def write(self, values): result = super(advance_rm_material, self).write(values) if self.fg_plan: self.fg_plan.state = self.state self.fg_plan.advance_rm_material_id = self.id return result @api.multi def name_get(self): result = [] for ai in self: b = datetime.strptime(ai.date, '%Y-%m-%d').strftime('%d %B %Y') name = str(ai.name) + ' ( ' + b + ' )' result.append((ai.id, name)) return result @api.constrains('average_forecast') def constraints_check(self): if self.average_forecast == 0: print "OOOOOOOOOOOOOOOOOOOOOOO Please enter Average Forecast" raise UserError("Please enter Average Forecast")