def unlink(self): for expense in self: if expense.state == "post": raise UserError(_("You cannot delete a posted expense.")) super(HrExpenseSheet, self).unlink()
def constraints_check(self): if not self.date_start and not self.date_end or self.date_start > self.date_end: raise UserError("Please select a valid date range")
def create(self, vals): # restrict the operation in case we are trying to set a forbidden field if self.company_id.country_id.code == 'FR' and vals.get('update_posted'): raise UserError(ERR_MSG % (self._name, 'update_posted')) return super(AccountJournal, self).create(vals)
def copy(self, cr, uid, id, default=None, context=None): raise UserError(_('Duplicating campaigns is not supported.'))
def _check_ticket_seats_limit(self): if self.event_ticket_id.seats_max and self.event_ticket_id.seats_available < 0: raise UserError(_('No more available seats for this ticket'))
def _check_seats_limit(self): if self.event_id.seats_availability == 'limited' and self.event_id.seats_max and self.event_id.seats_available < ( 1 if self.state == 'draft' else 0): raise UserError(_('No more seats available for this event.'))
def unlink(self): if self.state == ISSUE_STATE_CANCELED: return super(tracker_issue, self).unlink() else: raise UserError( _('You can\'t delete record with state not canceled.'))
def action_get_connection(self): self.ensure_one() afip_ws = self.afip_ws if not afip_ws: raise UserError(_('No AFIP WS selected')) self.company_id.get_connection(afip_ws).connect()
def get_pyafipws_currency_rate(self, currency): raise UserError( currency.get_pyafipws_currency_rate( afip_ws=self.afip_ws, company=self.company_id, )[1])
def copy(self, cr, uid, ids, *args, **argv): raise UserError(_('You cannot duplicate a timesheet.'))
def _check(self, cr, uid, ids): for att in self.browse(cr, uid, ids): if att.sheet_id and att.sheet_id.state not in ('draft', 'new'): raise UserError(_('You cannot modify an entry in a confirmed timesheet')) return True
def action_sync_sales(self): sesion = Session() informacion = sesion.get_session_info() bd = informacion.get('db') if bd[0:3] == 'GMM': unidades = [] limitante = "" obj_invoice = self.env['account.invoice'] obj_invoice_line = self.env['account.invoice.line'] obj_ir_attachment_facturae = self.env['ir.attachment.facturae.mx'] obj_sales_log = self.env['sync.sales.log'] attachment = self.env['ir.attachment'] obj_invoice_tax = self.env['account.invoice.tax'] if self.unit_process: query_ou = ("select id from operating_unit") self.env.cr.execute(query_ou) operating_unit = self.env.cr.fetchall() for reg in operating_unit: unidades.append(reg[0]) else: if self.ou: for reg in self.ou: unidades.append(reg.id) else: raise UserError(('Seleccionar una o mas unidades operativas')) if self.num_registros > 0: limitante = "limit %s"%str(self.num_registros) for unidad in unidades: try: unit = self.env['operating.unit'].browse(unidad) """Se crea la conexion por cada unidad operativa que se selecciona""" con = psycopg2.connect("host='%s' port=none dbname='%s' user='******' password='******'"%(unit.ip_address,unit.data_base)) cursor = con.cursor() date_init = self.fecha_inicial.replace('-','') date_end = self.fecha_final.replace('-','') query_sales = ("""select f.id_factura, f.numdocto, '['|| f.numcte::text || '-' || f.numsocio::text || ']' refcli, importe, iva, f.subtotal, f.importe_iva, f.importe_descuento, trim(cast(substr(fecha_gen::Text,1,10)||'T'||substr(fecha_gen::Text,12,8) as char(19))) fecha, f.fechaven, trim(f.serie) serie, parte_rel, tipo_venta, folio_fiscal, c.nombre, replace(c.rfc, '-','') rfc, s.cfdi_xml from cxcfacturas f inner join cxcclientes c on f.numcte=c.numcte left join cfdi_sellado s on f.serie=s.serie and f.numdocto=s.numdocto where fechadoc between %s and %s and tipomov=110 order by numdocto %s;"""%(date_init,date_end,limitante)) #and paso_erp = 0::bit clausula pendiente de agregar al query cursor.execute(query_sales) registros = cursor.fetchall() id_facturas = [] if registros: for reg in registros: """ARREGLO CON LOS IDS DE LAS FACTURAS DEL SERVIDOR DE GM""" id_facturas.append(reg[0]) """LOGICA PARA SELECCIONAR LA CUENTA CORRECTA EN EL ENCABEZADO Y DETALLADO DE LA FACTURA""" if reg[11] == 'S': ai_acc = self.cliente_pr.property_account_receibavle.id ail_acc = self.cuenta_ventas_pr.id elif reg[12] == 'C': ail_acc = self.cuenta_ventas_contado.id else: ai_acc = unit.partner_id.property_account_receivable.id ail_acc = self.cuenta_ventas_credito.id date_inv = reg[8] date_invoice = date_inv[0:10] date_due = datetime.strptime(str(reg[9]), '%Y%m%d') fecha_ven = datetime.strftime(date_due,'%Y-%m-%d') #ENCABEZADO DE LA FACTURA invoice_header = { 'partner_id': unit.partner_id.id, 'account_id': ai_acc, 'journal_id': 1,#preguntar que diario usar 'operating_unit_id' : unit.id, 'type' : 'out_invoice', 'origin' : str(reg[0]), 'date_invoice': date_invoice, 'date_due' : fecha_ven, 'number': reg[10] + '-' + str(reg[1]), 'internal_number': reg[10] + '-' + str(reg[1]), 'reference': reg[2]+' '+ reg[14].strip(), 'name': reg[15] + reg[2], 'origin': str(reg[0]), } #SE CREA LA FACTURA invoice = obj_invoice.create(invoice_header) """LOGICA PARA CREAR EL ATTACHMENT CON EL XML DE LA FACTURA""" if reg[16]: xml = reg[16] xml_file = self._checking_characters(xml) invoice_attachment = { 'name':unit.partner_id.vat_split + '.xml', 'type': 'binary', 'datas': xml_file.encode('base64'), 'res_model': 'account.invoice', 'datas_fname': unit.partner_id.vat_split + '_' + reg[10] + '-' + str(reg[1]), 'res_id': invoice.id, } attch = attachment.create(invoice_attachment) """LOGICA PARA ASIGNAR EL UUID A LA FACTURA CREADA EL UUID SE SACA DEL REGISTRO DONDE SE CREA EL ATTACHMENT""" if reg[13]: attachment_facturae = { 'name':reg[10] + '-' + str(reg[1]), 'uuid' : reg[13], 'state': 'done', 'company_id':1, 'cfdi_type' : 'incoming', 'file_xml_sign': attch.id, 'type_attachment': 'account.invoice', 'res_id':invoice.id, } obj_ir_attachment_facturae.create(attachment_facturae) """LINEAS DE LA FACTURA""" invoice_line = { 'name': reg[2]+' '+ reg[14].strip(), 'account_id' : ail_acc, 'quantity': 1, 'price_unit': reg[5] - reg[7], 'uos_id': 1, 'invoice_line_tax_id': [ (6, 0, [self.impuesto.id]), ], 'invoice_id': invoice.id, } #SE CREAN LAS LINEAS DE LA FACTURA obj_invoice_line.create(invoice_line) """SE ACTUALIZA LA LINEA DE IMPUESTOS PARA DESPUES ASIGNARLE DE MANERA MANUAL EL IMPORTE CORRECTO DEL IMPUESTO""" invoice.button_reset_taxes() invoice_tax = obj_invoice_tax.search([('invoice_id', '=', invoice.id)]) update_amount = { 'amount': reg[6], } invoice_tax.update(update_amount) """SE VALIDA LA FACTURA""" invoice.invoice_open() else: raise UserError(('No se encontraron registros en las fechas seleccionadas')) except: """EXCEPCION PARA LAS UNIDADES OPERATIVAS QUE NO PUDIERON CONECTARSE A SUS RESPECTIVAS BASE DE DATOS Y SE CREA EL REGISTRO EN UN LOG DE SINCRONIZACION DE VENTAS EN DONDE SE MUESTRAN LAS UNIDADES OPERATIVAS QUE NO SE PUDIERON CONECTAR A SU RESPECTIVO SERVIDOR """ print"ENTRE AL EXCEPCTION POR LA UNIDAD:", unit.name sales_log = { 'operating_unit' : unit.name, 'message' : 'Conexion refusada favor de checar parametros IP addres y Base de datos', 'ip_addres' : unit.ip_address, 'data_base' : unit.data_base, } obj_sales_log.create(sales_log) """QUERY DE ACTUALIZACION A PETICION EN EL REQUERIMIENTO""" #query_update = ("update cxcfacturas set paso_erp = 1::bit where id_factura in %s"%str((tuple(id_facturas)))) #cursor.execute(query_update) else: raise UserError(("Base de datos erronea favor de correr el proceso en la base de datos GMM"))
def unlink(self): if any(rec.state != 'draft' for rec in self): raise UserError(_("You can not delete a payment that is already posted")) return super(account_payment, self).unlink()
def import_pol_apply(self): pol_obj = self.env['purchase.order.line'] #perform import lead if self and self.file and self.env.context.get('sh_po_id', False): #For CSV if self.import_type == 'csv': counter = 1 skipped_line_no = {} try: file = str(base64.decodestring(self.file).decode('utf-8')) myreader = csv.reader(file.splitlines()) skip_header = True for row in myreader: try: if skip_header: skip_header = False counter = counter + 1 continue if row[0] != '': vals = {} field_nm = 'name' if self.product_by == 'name': field_nm = 'name' elif self.product_by == 'int_ref': field_nm = 'default_code' elif self.product_by == 'barcode': field_nm = 'barcode' search_product = self.env[ 'product.product'].search( [(field_nm, '=', row[0])], limit=1) if search_product: vals.update( {'product_id': search_product.id}) if row[1] != '': vals.update({'name': row[1]}) else: vals.update( {'name': search_product.name}) active_po = self.env[ 'purchase.order'].search([ ('id', '=', self.env.context.get( 'sh_po_id')) ]) if active_po: product_lang = search_product.with_context( { 'lang': active_po.partner_id.lang, 'partner_id': active_po.partner_id.id, }) pro_desc = product_lang.display_name if product_lang.description_purchase: pro_desc += '\n' + product_lang.description_purchase vals.update({'name': pro_desc}) if row[2] != '': vals.update({'product_qty': row[2]}) else: vals.update({'product_qty': 1}) if row[3] in ( None, "") and search_product.uom_po_id: vals.update({ 'product_uom': search_product.uom_po_id.id }) else: search_uom = self.env[ 'product.uom'].search( [('name', '=', row[3])], limit=1) if search_uom: vals.update( {'product_uom': search_uom.id}) else: skipped_line_no[str( counter )] = " - Unit of Measure not found. " counter = counter + 1 continue if row[4] in (None, ""): vals.update({ 'price_unit': search_product.standard_price }) else: vals.update({'price_unit': row[4]}) if row[5].strip() in ( None, "" ) and search_product.supplier_taxes_id: vals.update({ 'taxes_id': [(6, 0, search_product. supplier_taxes_id.ids)] }) else: taxes_list = [] some_taxes_not_found = False for x in row[5].split(','): x = x.strip() if x != '': search_tax = self.env[ 'account.tax'].search( [('name', '=', x)], limit=1) if search_tax: taxes_list.append( search_tax.id) else: some_taxes_not_found = True skipped_line_no[str( counter )] = " - Taxes " + x + " not found. " break if some_taxes_not_found: counter = counter + 1 continue else: vals.update({ 'taxes_id': [(6, 0, taxes_list)] }) if row[6] in (None, ""): vals.update( {'date_planned': datetime.now()}) else: cd = row[6] cd = str( datetime.strptime( cd, '%Y-%m-%d').date()) vals.update({"date_planned": cd}) else: skipped_line_no[str( counter)] = " - Product not found. " counter = counter + 1 continue vals.update({ 'order_id': self.env.context.get('sh_po_id') }) created_pol = pol_obj.create(vals) counter = counter + 1 else: skipped_line_no[str( counter)] = " - Product is empty. " counter = counter + 1 except Exception as e: skipped_line_no[str( counter)] = " - Value is not valid " + ustr(e) counter = counter + 1 continue except Exception: raise UserError( _("Sorry, Your csv file does not match with our format" )) if counter > 1: completed_records = (counter - len(skipped_line_no)) - 2 res = self.show_success_msg(completed_records, skipped_line_no) return res #For Excel if self.import_type == 'excel': counter = 1 skipped_line_no = {} try: wb = xlrd.open_workbook( file_contents=base64.decodestring(self.file)) sheet = wb.sheet_by_index(0) skip_header = True for row in range(sheet.nrows): try: if skip_header: skip_header = False counter = counter + 1 continue if sheet.cell(row, 0).value != '': vals = {} field_nm = 'name' if self.product_by == 'name': field_nm = 'name' elif self.product_by == 'int_ref': field_nm = 'default_code' elif self.product_by == 'barcode': field_nm = 'barcode' search_product = self.env[ 'product.product'].search( [(field_nm, '=', sheet.cell(row, 0).value)], limit=1) if search_product: vals.update( {'product_id': search_product.id}) if sheet.cell(row, 1).value != '': vals.update( {'name': sheet.cell(row, 1).value}) else: vals.update( {'name': search_product.name}) active_po = self.env[ 'purchase.order'].search([ ('id', '=', self.env.context.get( 'sh_po_id')) ]) if active_po: product_lang = search_product.with_context( { 'lang': active_po.partner_id.lang, 'partner_id': active_po.partner_id.id, }) pro_desc = product_lang.display_name if product_lang.description_purchase: pro_desc += '\n' + product_lang.description_purchase vals.update({'name': pro_desc}) if sheet.cell(row, 2).value != '': vals.update({ 'product_qty': sheet.cell(row, 2).value }) else: vals.update({'product_qty': 1}) if sheet.cell(row, 3).value in ( None, "") and search_product.uom_po_id: vals.update({ 'product_uom': search_product.uom_po_id.id }) else: search_uom = self.env[ 'product.uom'].search( [('name', '=', sheet.cell(row, 3).value)], limit=1) if search_uom: vals.update( {'product_uom': search_uom.id}) else: skipped_line_no[str( counter )] = " - Unit of Measure not found. " counter = counter + 1 continue if sheet.cell(row, 4).value in (None, ""): vals.update({ 'price_unit': search_product.standard_price }) else: vals.update({ 'price_unit': sheet.cell(row, 4).value }) if sheet.cell(row, 5).value.strip() in ( None, "" ) and search_product.supplier_taxes_id: vals.update({ 'taxes_id': [(6, 0, search_product. supplier_taxes_id.ids)] }) else: taxes_list = [] some_taxes_not_found = False for x in sheet.cell( row, 5).value.split(','): x = x.strip() if x != '': search_tax = self.env[ 'account.tax'].search( [('name', '=', x)], limit=1) if search_tax: taxes_list.append( search_tax.id) else: some_taxes_not_found = True skipped_line_no[str( counter )] = " - Taxes " + x + " not found. " break if some_taxes_not_found: counter = counter + 1 continue else: vals.update({ 'taxes_id': [(6, 0, taxes_list)] }) if sheet.cell(row, 6).value in (None, ""): vals.update( {'date_planned': datetime.now()}) else: cd = sheet.cell(row, 6).value cd = str( datetime.strptime( cd, '%Y-%m-%d').date()) vals.update({"date_planned": cd}) else: skipped_line_no[str( counter)] = " - Product not found. " counter = counter + 1 continue vals.update({ 'order_id': self.env.context.get('sh_po_id') }) created_pol = pol_obj.create(vals) counter = counter + 1 else: skipped_line_no[str( counter)] = " - Product is empty. " counter = counter + 1 except Exception as e: skipped_line_no[str( counter)] = " - Value is not valid " + ustr(e) counter = counter + 1 continue except Exception: raise UserError( _("Sorry, Your excel file does not match with our format" )) if counter > 1: completed_records = (counter - len(skipped_line_no)) - 2 res = self.show_success_msg(completed_records, skipped_line_no) return res
def _check_seats_limit(self): if self.seats_availability == 'limited' and self.seats_max and self.seats_available < 0: raise UserError(_('No more available seats.'))
def check_afip_ws_and_type(self): if self.point_of_sale_type != 'electronic' and self.afip_ws: raise UserError( _('You can only use an AFIP WS if type is "Electronic"'))
def _check_closing_date(self): if self.date_end < self.date_begin: raise UserError( _('Closing Date cannot be set before Beginning Date.'))
def write(self,values): for record in self: if len(record.voyage_ids)==0: raise UserError(_('Veuillez spécifier les voyages de la feuille de route')) record = super(TransportFeuilleRoute, self.with_context(mail_create_nolog=True)).write(values) return record
def copy(self, *args, **kwargs): raise UserError( _('Is not possible to duplicate an issue, please create a new one.' ))
def compute_refund(self, mode='refund'): inv_obj = self.env['account.invoice'] inv_tax_obj = self.env['account.invoice.tax'] inv_line_obj = self.env['account.invoice.line'] context = dict(self._context or {}) xml_id = False for form in self: created_inv = [] date = False description = False for inv in inv_obj.browse(context.get('active_ids')): if inv.state in ['draft', 'proforma2', 'cancel']: raise UserError( _('Cannot refund draft/proforma/cancelled invoice.')) if inv.reconciled and mode in ('cancel', 'modify'): raise UserError( _('Cannot refund invoice which is already reconciled, invoice should be unreconciled first. You can only refund this invoice.' )) date = form.date or False description = form.description or inv.name refund = inv.refund(form.date_invoice, date, description, inv.journal_id.id) refund.compute_taxes() created_inv.append(refund.id) if mode in ('cancel', 'modify'): movelines = inv.move_id.line_ids to_reconcile_ids = {} to_reconcile_lines = self.env['account.move.line'] for line in movelines: if line.account_id.id == inv.account_id.id: to_reconcile_lines += line to_reconcile_ids.setdefault( line.account_id.id, []).append(line.id) if line.reconciled: line.remove_move_reconcile() refund.signal_workflow('invoice_open') for tmpline in refund.move_id.line_ids: if tmpline.account_id.id == inv.account_id.id: to_reconcile_lines += tmpline to_reconcile_lines.reconcile() if mode == 'modify': invoice = inv.read([ 'name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_insite', 'partner_contact', 'partner_ref', 'payment_term_id', 'account_id', 'currency_id', 'invoice_line_ids', 'tax_line_ids', 'journal_id', 'date' ]) invoice = invoice[0] del invoice['id'] invoice_lines = inv_line_obj.browse( invoice['invoice_line_ids']) invoice_lines = inv_obj.with_context( mode='modify')._refund_cleanup_lines(invoice_lines) tax_lines = inv_tax_obj.browse(invoice['tax_line_ids']) tax_lines = inv_obj._refund_cleanup_lines(tax_lines) invoice.update({ 'type': inv.type, 'date_invoice': form.date_invoice, 'state': 'draft', 'number': False, 'invoice_line_ids': invoice_lines, 'tax_line_ids': tax_lines, 'date': date, 'name': description }) for field in ('partner_id', 'account_id', 'currency_id', 'payment_term_id', 'journal_id'): invoice[ field] = invoice[field] and invoice[field][0] inv_refund = inv_obj.create(invoice) if inv_refund.payment_term_id.id: inv_refund._onchange_payment_term_date_invoice() created_inv.append(inv_refund.id) xml_id = (inv.type in ['out_refund', 'out_invoice']) and 'action_invoice_tree1' or \ (inv.type in ['in_refund', 'in_invoice']) and 'action_invoice_tree2' # Put the reason in the chatter subject = _("Invoice refund") body = description refund.message_post(body=body, subject=subject) if xml_id: result = self.env.ref('account.%s' % (xml_id)).read()[0] invoice_domain = eval(result['domain']) invoice_domain.append(('id', 'in', created_inv)) result['domain'] = invoice_domain return result return True
def action_move_create(self): """ Creates invoice related analytics and financial move lines """ account_move = self.env['account.move'] for inv in self: if not inv.journal_id.sequence_id: raise UserError( _('Please define sequence on the journal related to this invoice.' )) if not inv.invoice_line_ids: raise UserError(_('Please create some invoice lines.')) if inv.move_id: continue ctx = dict(self._context, lang=inv.partner_id.lang) if not inv.date_invoice: inv.with_context(ctx).write( {'date_invoice': fields.Date.context_today(self)}) date_invoice = inv.date_invoice company_currency = inv.company_id.currency_id # create move lines (one per invoice line + eventual taxes and analytic lines) iml = inv.invoice_line_move_line_get() iml += inv.tax_line_move_line_get() iml += inv.invoice_delivery_charge_get() diff_currency = inv.currency_id != company_currency # create one move line for the total and possibly adjust the other lines amount total, total_currency, iml = inv.with_context( ctx).compute_invoice_totals(company_currency, iml) name = inv.name or '/' if inv.payment_term_id: totlines = inv.with_context(ctx).payment_term_id.with_context( currency_id=inv.currency_id.id).compute( total, date_invoice)[0] res_amount_currency = total_currency ctx['date'] = date_invoice for i, t in enumerate(totlines): if inv.currency_id != company_currency: amount_currency = company_currency.with_context( ctx).compute(t[1], inv.currency_id) else: amount_currency = False # last line: add the diff res_amount_currency -= amount_currency or 0 if i + 1 == len(totlines): amount_currency += res_amount_currency iml.append({ 'type': 'dest', 'name': name, 'price': t[1], 'account_id': inv.account_id.id, 'date_maturity': t[0], 'amount_currency': diff_currency and amount_currency, 'currency_id': diff_currency and inv.currency_id.id, 'invoice_id': inv.id }) else: iml.append({ 'type': 'dest', 'name': name, 'price': total, 'account_id': inv.account_id.id, 'date_maturity': inv.date_due, 'amount_currency': diff_currency and total_currency, 'currency_id': diff_currency and inv.currency_id.id, 'invoice_id': inv.id }) part = self.env['res.partner']._find_accounting_partner( inv.partner_id) line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml] line = inv.group_lines(iml, line) journal = inv.journal_id.with_context(ctx) line = inv.finalize_invoice_move_lines(line) date = inv.date or date_invoice move_vals = { 'ref': inv.reference, 'line_ids': line, 'journal_id': journal.id, 'date': date, 'narration': inv.comment, } ctx['company_id'] = inv.company_id.id ctx['dont_create_taxes'] = True ctx['invoice'] = inv ctx_nolang = ctx.copy() ctx_nolang.pop('lang', None) move = account_move.with_context(ctx_nolang).create(move_vals) # Pass invoice in context in method post: used if you want to get the same # account move reference when creating the same invoice after a cancelled one: move.post() # make the invoice point to that move vals = { 'move_id': move.id, 'date': date, 'move_name': move.name, } inv.with_context(ctx).write(vals) return True
def _check_date(self): for template in self: if template.start_datetime >= template.end_datetime: raise UserError( _("End datetime should greater than Start Datetime"))
def _check_seats_limit(self): if self.seats_max and self.seats_available < 0: raise UserError(_('No more available seats for the ticket'))
def _check_seats_limit(self): for templ in self: if templ.seats_availability == 'limited' and templ.seats_max and\ templ.seats_available < 0: raise UserError(_('No more available seats.'))
def unlink(self): for order in self: if order.state != 'draft': raise UserError(_('You can only delete Draft Entries')) return super(sales_declaration, self).unlink()
def _check_duration(self): if self.date_stop and self.date_start and \ self.date_stop < self.date_start: raise UserError( _('Error ! The duration of the\ Month(s) is/are invalid.'))
def write(self, vals): # restrict the operation in case we are trying to write a forbidden field if set(vals).intersection(LINE_FIELDS): if any(l.company_id.country_id.code == 'FR' and l.move_id.state == 'posted' for l in self): raise UserError(ERR_MSG % (self._name, ', '.join(LINE_FIELDS))) return super(AccountMoveLine, self).write(vals)
def _check_duration(self): if self.date_stop and self.date_start: if self.date_stop < self.date_start: raise UserError( _('Error! The duration of the academic \ year is invalid.'))
def button_cancel(self): #by-pass the normal behavior/message that tells people can cancel a posted journal entry #if the journal allows it. if self.company_id.country_id.code == 'FR': raise UserError(_('You cannot modify a posted entry of a journal.')) super(AccountMove, self).button_cancel()
def _move_line_get(self): account_move = [] for expense in self: if expense.account_id: account = expense.account_id elif expense.product_id: account = expense.product_id.product_tmpl_id._get_product_accounts( )['expense'] if not account: raise UserError( _("No Expense account found for the product %s (or for it's category), please configure one." ) % (expense.product_id.name)) else: account = self.env['ir.property'].with_context( force_company=expense.company_id.id).get( 'property_account_expense_categ_id', 'product.category') if not account: raise UserError( _('Please configure Default Expense account for Product expense: `property_account_expense_categ_id`.' )) aml_name = expense.employee_id.name + ': ' + expense.name.split( '\n')[0][:64] move_line = { 'type': 'src', 'name': aml_name, 'price_unit': expense.unit_amount, 'quantity': expense.quantity, 'price': expense.total_amount, 'account_id': account.id, 'product_id': expense.product_id.id, 'uom_id': expense.product_uom_id.id, 'analytic_account_id': expense.analytic_account_id.id, } account_move.append(move_line) # Calculate tax lines and adjust base line taxes = expense.tax_ids.compute_all(expense.unit_amount, expense.currency_id, expense.quantity, expense.product_id) account_move[-1]['price'] = taxes['total_excluded'] account_move[-1]['tax_ids'] = expense.tax_ids.ids for tax in taxes['taxes']: account_move.append({ 'type': 'tax', 'name': tax['name'], 'price_unit': tax['amount'], 'quantity': 1, 'price': tax['amount'], 'account_id': tax['account_id'] or move_line['account_id'], 'tax_line_id': tax['id'], }) return account_move