Beispiel #1
0
class AccountPayment(models.Model):

    _inherit = 'account.payment'
    # _name = 'account.check'
    # _description = 'Account Check'
    # _order = "id desc"
    # _inherit = ['mail.thread']

    # communication = fields.Char(
    #     # because onchange function is not called on onchange and we want
    #     # to clean check number name
    #     copy=False,
    # )
    # TODO tal vez renombrar a check_ids
    check_ids = fields.Many2many(
        'account.check',
        # 'account.move.line',
        # 'check_deposit_id',
        string='Checks',
        copy=False,
        readonly=True,
        states={'draft': [('readonly', '=', False)]}
    )
    # only for v8 comatibility where more than one check could be received
    # or issued
    check_ids_copy = fields.Many2many(
        related='check_ids',
        readonly=True,
    )
    readonly_currency_id = fields.Many2one(
        related='currency_id',
        readonly=True,
    )
    readonly_amount = fields.Monetary(
        # string='Payment Amount',
        # required=True
        related='amount',
        readonly=True,
    )
    # we add this field for better usability on issue checks and received
    # checks. We keep m2m field for backward compatibility where we allow to
    # use more than one check per payment
    check_id = fields.Many2one(
        'account.check',
        compute='_compute_check',
        string='Check',
        # string='Payment Amount',
        # required=True
    )

    @api.multi
    @api.depends('check_ids')
    def _compute_check(self):
        for rec in self:
            # we only show checks for issue checks or received thid checks
            # if len of checks is 1
            if rec.payment_method_code in (
                    'received_third_check',
                    'issue_check',) and len(rec.check_ids) == 1:
                rec.check_id = rec.check_ids[0].id

# check fields, just to make it easy to load checks without need to create
# them by a m2o record
    check_name = fields.Char(
        'Check Name',
        # required=True,
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]},
    )
    check_number = fields.Integer(
        'Check Number',
        # required=True,
        readonly=True,
        states={'draft': [('readonly', False)]},
        copy=False
    )
    check_issue_date = fields.Date(
        'Check Issue Date',
        # required=True,
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]},
        default=fields.Date.context_today,
    )
    check_payment_date = fields.Date(
        'Check Payment Date',
        readonly=True,
        help="Only if this check is post dated",
        states={'draft': [('readonly', False)]}
    )
    checkbook_id = fields.Many2one(
        'account.checkbook',
        'Checkbook',
        readonly=True,
        states={'draft': [('readonly', False)]},
        # TODO hacer con un onchange
        # default=_get_checkbook,
    )
    check_subtype = fields.Selection(
        related='checkbook_id.issue_check_subtype',
    )
    check_bank_id = fields.Many2one(
        'res.bank',
        'Check Bank',
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]}
    )
    check_owner_vat = fields.Char(
        # TODO rename to Owner VAT
        'Check Owner Vat',
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]}
    )
    check_owner_name = fields.Char(
        'Check Owner Name',
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]}
    )
    check_type = fields.Char(
        compute='_compute_check_type',
        # this fields is to help with code and view
    )

    @api.multi
    @api.depends('payment_method_code')
    def _compute_check_type(self):
        for rec in self:
            if rec.payment_method_code == 'issue_check':
                rec.check_type = 'issue_check'
            elif rec.payment_method_code in [
                    'received_third_check',
                    'delivered_third_check']:
                rec.check_type = 'third_check'


# on change methods

    # @api.constrains('check_ids')
    @api.onchange('check_ids', 'payment_method_code')
    def onchange_checks(self):
        # we only overwrite if payment method is delivered
        if self.payment_method_code == 'delivered_third_check':
            self.amount = sum(self.check_ids.mapped('amount'))

    # TODo activar
    @api.one
    @api.onchange('check_number', 'checkbook_id')
    def change_check_number(self):
        # TODO make default padding a parameter
        if self.payment_method_code in ['received_third_check']:
            if not self.check_number:
                check_name = False
            else:
                # TODO make optional
                padding = 8
                if len(str(self.check_number)) > padding:
                    padding = len(str(self.check_number))
                # communication = _('Check nbr %s') % (
                check_name = ('%%0%sd' % padding % self.check_number)
                # communication = (
                #     '%%0%sd' % padding % self.check_number)
            self.check_name = check_name

    @api.onchange('check_issue_date', 'check_payment_date')
    def onchange_date(self):
        if (
                self.check_issue_date and self.check_payment_date and
                self.check_issue_date > self.check_payment_date):
            self.check_payment_date = False
            raise UserError(
                _('Check Payment Date must be greater than Issue Date'))

    @api.one
    @api.onchange('partner_id')
    def onchange_partner_check(self):
        commercial_partner = self.partner_id.commercial_partner_id
        self.check_bank_id = (
            commercial_partner.bank_ids and
            commercial_partner.bank_ids[0].bank_id.id or False)
        self.check_owner_name = commercial_partner.name
        # TODO use document number instead of vat?
        self.check_owner_vat = commercial_partner.vat

    @api.onchange('payment_method_code')
    def _onchange_payment_method_code(self):
        if self.payment_method_code == 'issue_check':
            checkbook = self.env['account.checkbook'].search([
                ('state', '=', 'active'),
                ('journal_id', '=', self.journal_id.id)],
                limit=1)
            self.checkbook_id = checkbook

    @api.onchange('checkbook_id')
    def onchange_checkbook(self):
        if self.checkbook_id:
            self.check_number = self.checkbook_id.next_number


# post methods
    @api.model
    def create(self, vals):
        issue_checks = self.env.ref(
            'account_check.account_payment_method_issue_check')
        if vals['payment_method_id'] == issue_checks.id and vals.get(
                'checkbook_id'):
            checkbook = self.env['account.checkbook'].browse(
                vals['checkbook_id'])
            vals.update({
                # beacause number was readonly we write it here
                'check_number': checkbook.next_number,
                'check_name': checkbook.sequence_id.next_by_id(),
            })
        return super(AccountPayment, self.sudo()).create(vals)

    @api.multi
    def cancel(self):
        res = super(AccountPayment, self).cancel()
        for rec in self:
            rec.do_checks_operations(cancel=True)
            # if rec.check_id:
            #     # rec.check_id._add_operation('cancel')
            #     rec.check_id._del_operation()
            #     rec.check_id.unlink()
            # elif rec.check_ids:
            #     rec.check_ids._del_operation()
        return res

    @api.multi
    def create_check(self, check_type, operation, bank):
        self.ensure_one()

        check_vals = {
            'bank_id': bank.id,
            'owner_name': self.check_owner_name,
            'owner_vat': self.check_owner_vat,
            'number': self.check_number,
            'name': self.check_name,
            'checkbook_id': self.checkbook_id.id,
            'issue_date': self.check_issue_date,
            'type': self.check_type,
            'journal_id': self.journal_id.id,
            'amount': self.amount,
            'payment_date': self.check_payment_date,
            # TODO arreglar que monto va de amount y cual de amount currency
            # 'amount_currency': self.amount,
            'currency_id': self.currency_id.id,
        }
        check = self.env['account.check'].create(check_vals)
        self.check_ids = [(4, check.id, False)]
        check._add_operation(operation, self, self.partner_id)
        return check

    @api.multi
    def get_third_check_account(self):
        """
        For third checks, if we use a journal only for third checks, we use
        accounts on journal, if not we use company account
        """
        self.ensure_one()
        if self.payment_type in ('outbound', 'transfer'):
            account = self.journal_id.default_debit_account_id
            methods_field = 'outbound_payment_method_ids'
        else:
            account = self.journal_id.default_credit_account_id
            methods_field = 'inbound_payment_method_ids'
        if len(self.journal_id[methods_field]) > 1 or not account:
            account = self.company_id._get_check_account('holding')
        return account

    @api.multi
    def do_checks_operations(self, vals=None, cancel=False):
        """
        Check attached .ods file on this module to understand checks workflows
        This method is called from:
        * cancellation of payment to execute delete the right operation and
            unlink check if needed
        * from _get_liquidity_move_line_vals to add check operation and, if
            needded, change payment vals and/or create check and
        """
        self.ensure_one()
        rec = self
        if not rec.check_type:
            # continue
            return vals
        if (
                rec.payment_method_code == 'received_third_check' and
                rec.payment_type == 'inbound' and
                rec.partner_type == 'customer'):
            operation = 'holding'
            if cancel:
                _logger.info('Cancel Receive Check')
                rec.check_ids._del_operation(operation)
                rec.check_ids.unlink()
                return None

            _logger.info('Receive Check')
            self.create_check('third_check', operation, self.check_bank_id)
            vals['date_maturity'] = self.check_payment_date
            vals['account_id'] = self.get_third_check_account().id
        elif (
                rec.payment_method_code == 'delivered_third_check' and
                rec.payment_type == 'transfer' and
                rec.destination_journal_id.type == 'cash'):
            operation = 'selled'
            if cancel:
                _logger.info('Cancel Sell Check')
                rec.check_ids._del_operation(operation)
                return None

            _logger.info('Sell Check')
            rec.check_ids._add_operation(
                operation, rec, False)
            vals['account_id'] = self.get_third_check_account().id
        elif (
                rec.payment_method_code == 'delivered_third_check' and
                rec.payment_type == 'transfer' and
                rec.destination_journal_id.type == 'bank'):
            operation = 'deposited'
            if cancel:
                _logger.info('Cancel Deposit Check')
                rec.check_ids._del_operation(operation)
                return None

            _logger.info('Deposit Check')
            rec.check_ids._add_operation(
                operation, rec, False)
            vals['account_id'] = self.get_third_check_account().id
        elif (
                rec.payment_method_code == 'delivered_third_check' and
                rec.payment_type == 'outbound' and
                rec.partner_type == 'supplier'):
            operation = 'delivered'
            if cancel:
                _logger.info('Cancel Deliver Check')
                rec.check_ids._del_operation(operation)
                return None

            _logger.info('Deliver Check')
            rec.check_ids._add_operation(
                operation, rec, rec.partner_id)
            vals['account_id'] = self.get_third_check_account().id
        elif (
                rec.payment_method_code == 'issue_check' and
                rec.payment_type == 'outbound' and
                rec.partner_type == 'supplier'):
            operation = 'handed'
            if cancel:
                _logger.info('Cancel Hand Check')
                rec.check_ids._del_operation(operation)
                rec.check_ids.unlink()
                return None

            _logger.info('Hand Check')
            self.create_check('issue_check', operation, self.check_bank_id)
            vals['date_maturity'] = self.check_payment_date
            # if check is deferred, change account
            if self.check_subtype == 'deferred':
                vals['account_id'] = self.company_id._get_check_account(
                    'deferred').id
        elif (
                rec.payment_method_code == 'issue_check' and
                rec.payment_type == 'transfer' and
                rec.destination_journal_id.type == 'cash'):
            operation = 'withdrawed'
            if cancel:
                _logger.info('Cancel Withdrawal Check')
                rec.check_ids._del_operation(operation)
                rec.check_ids.unlink()
                return None

            _logger.info('Hand Check')
            self.create_check('issue_check', operation, self.check_bank_id)
            vals['date_maturity'] = self.check_payment_date
            # if check is deferred, change account
            # si retiramos por caja directamente lo sacamos de banco
            # if self.check_subtype == 'deferred':
            #     vals['account_id'] = self.company_id._get_check_account(
            #         'deferred').id
        else:
            raise UserError(_(
                'This operatios is not implemented for checks:\n'
                '* Payment type: %s\n'
                '* Partner type: %s\n'
                '* Payment method: %s\n'
                '* Destination journal: %s\n' % (
                    rec.payment_type,
                    rec.partner_type,
                    rec.payment_method_code,
                    rec.destination_journal_id.type)))
        return vals

    # @api.multi
    # def post(self):
    #     self.do_checks_operations()
    #     return super(AccountPayment, self).post()

    def _get_liquidity_move_line_vals(self, amount):
        vals = super(AccountPayment, self)._get_liquidity_move_line_vals(
            amount)
        vals = self.do_checks_operations(vals=vals)
        # if self.check_type:
        #     vals['date_maturity'] = self.check_payment_date
        #     if self.check_subtype == 'deferred':
        #         deferred_account = self.company_id.deferred_check_account_id
        #         if not deferred_account:
        #             raise UserError(_(
        #                 'No checks deferred account defined for company %s'
        #             ) % self.company_id.name)
        #         vals['account_id'] = deferred_account.id
        #     # vals['check_bank_id'] = self.check_bank_id.id
        #     # vals['check_owner_name'] = self.check_owner_name
        #     # vals['check_owner_vat'] = self.check_owner_vat
        #     # vals['check_number'] = self.check_number
        #     # vals['checkbook_id'] = self.checkbook_id.id
        #     # vals['check_issue_date'] = self.check_issue_date
        #     # if self.payment_method_code == 'issue_check':
        #     #     vals['check_type'] = 'issue_check'
        #     # else:
        #     #     vals['check_type'] = 'third_check'
        return vals
Beispiel #2
0
class SparkProject(models.Model):
	_name = 'sparkit.sparkproject'
	_inherit = 'mail.thread'

	name = fields.Char(compute='_get_project_name', track_visibility='always')

	#---- Basic Project Information ----#
	community_id = fields.Many2one('sparkit.community', string="Community", required=True,
		domain=[('is_partnered', '=', True)], ondelete='cascade', track_visibility='onchange')
	facilitator_id = fields.Many2one('res.users', string="Facilitator", related="community_id.facilitator_id")
	community_number = fields.Char(related='community_id.community_number', track_visibility='onchange')
	community_name = fields.Char(related='community_id.name', track_visibility='onchange')
	category_id = fields.Many2one('sparkit.projectcategory', string="Category", required=True,
		track_visibility='onchange')
	subcategory_id = fields.Many2one('sparkit.projectsubcategory', string="Sub-Category",
		track_visibility='onchange')
	grant_agreement_date = fields.Date(string="Grant Agreement Date",
		track_visibility='onchange')
	grant_amount = fields.Float(string="Grant Amount - USD", track_visibility='onchange',
		compute='_get_usd_grant_amount', readonly=True)
	grant_amount_local = fields.Float(string="Grant Amount - Local Currency",
			track_visibility='onchange')
	country_id = fields.Many2one(related='community_id.country_id', readonly=True,
		track_visibility='onchange')
	currency_id = fields.Many2one(related='country_id.currency_id', readonly=True,
		store=True, track_visibility='onchange')
	exchange_rate = fields.Float(string="Exchange Rate", compute='_get_exchange_rate',
		store=True, track_visibility='onchange')

	#-- Donor Info --#
	donor_funded = fields.Boolean(string="Donor Funded")
	donor_ids = fields.One2many('sparkit.projectdonation', 'project_id',
		string="Project Donors")

	#-- Budgeted Contribution Summary --#
	spark_contribution = fields.Float(string="Spark", readonly=True,
		compute='_spark_contribution', store=True, track_visibility='onchange')
	spark_contribution_percent = fields.Float(string="Spark Contribution %",
		readonly=True, compute='_spark_contribution_percent', store=True,
		track_visibility='onchange')
	inkind_community_contribution = fields.Float(string="In-Kind Community Contribution",
		store=True, compute='_inkind_community_contribution')
	cash_community_contribution = fields.Float(string="Cash Community Contribution",
		store=True, compute='_cash_community_contribution')
	community_contribution = fields.Float(string="Community", readonly=True,
		compute='_community_contribution', store=True, track_visibility='onchange')
	community_contribution_percent = fields.Float(string="Community Contribution %",
		readonly=True, compute='_community_contribution_percent', store=True,
		track_visibility='onchange')
	fvs_contribution = fields.Float(string="FVS-AMADE", readonly=True,
		compute='_fvs_contribution', store=True,
		track_visibility='onchange')
	fvs_contribution_percent = fields.Float(string="FVS-AMADE Contribution %",
		readonly=True, compute='_fvs_contribution_percent', store=True,
		track_visibility='onchange')
	other_contribution = fields.Float(string="Other", readonly=True,
		compute='_other_contribution', store=True,
		track_visibility='onchange')
	other_contribution_percent = fields.Float(string="Other Contribution %",
		readonly=True, compute='_other_contribution_percent', store=True,
		track_visibility='onchange')
	total = fields.Float(string="Total Budget", readonly=True,
		compute='_total', store=True,
		help="Includes both Spark, community, FVS, and other contributions.",
		track_visibility='onchange')
	grant_surplus = fields.Float(string="Grant Surplus", readonly=True,
		compute='_grant_surplus', store=True, track_visibility='onchange',
		help="This field is calculated from the total budgeted items allocated to Spark and the overall grant size.")

	#---- Budget Information ----#
	budget_line_item_ids = fields.One2many('sparkit.projectbudgetitem', 'project_id',
		string="Budget Line Items", track_visibility='onchange')

	#--- Transactions ---#
	transaction_ids = fields.One2many('sparkit.transaction', 'project_id',
		string="Transactions", track_visibility='onchange')
	total_expenditure = fields.Float(string="Total Expenditure", readonly=True,
		store=True, compute='_get_total_expenditure', track_visibility='onchange')
	bank_balance = fields.Float(string="Bank Balance", track_visibility='onchange')
	outstanding_receipts = fields.Float(string="Outstanding Receipts", readonly=True,
		store=True, compute='_get_outstanding_receipts', track_visibility='onchange')
	outstanding_receipts_dollars = fields.Float(string="Outstanding Receipts - $",
		store=True, compute='_get_oustanding_receipt_dollars')

	#-- Disbursals --#
	disbursal_ids = fields.One2many('sparkit.disbursal', 'project_id',
		string="Disbursals", track_visibility='onchange')
	number_disbursals = fields.Integer(readonly=True, store=True,
		compute='_get_number_disbursals', string="Number of Disbursals",
		track_visibility='onchange')
	total_disbursed = fields.Float(readonly=True, store=True,
		compute='_get_total_disbursed', string="Total Disbursed",
		track_visibility='onchange')
	left_to_disburse = fields.Float(string="Left to Disburse", readonly=True,
		store=True, compute='_get_left_to_disburse', track_visibility='onchange')
	last_disbursal_date = fields.Date(string="Last Disbursement",
		compute='get_last_disbursement', track_visibility='onchange')

	#-- Disbursal Requests--#
	disbursal_request_ids = fields.One2many('sparkit.disbursalrequest', 'project_id',
		string="Disbursal Requests", track_visibility='onchange')
	number_requests = fields.Integer(string="Number of Disbursal Requests", readonly=True,
		store=True, compute='_get_number_disbursal_requests', track_visibility='onchange')

	#-- Project Support Initiatives --#
	project_support_initiative_ids = fields.One2many('sparkit.projectsupportinitiative', 'project_id',
		string="Project Support Initiatives", track_visibility='onchange')


	#This function counts the number of disbursal requests made by the community
	@api.multi
	@api.depends('disbursal_request_ids')
	def _get_number_disbursal_requests(self):
		for r in self:
			r.number_requests = len(r.disbursal_request_ids)


	# Calculates exchange rate when budget is formed
	@api.multi
	@api.depends('currency_id')
	def _get_exchange_rate(self):
		for r in self:
			if r.currency_id:
				r.exchange_rate = r.currency_id.rate

	@api.multi
	@api.depends('disbursal_ids')
	def get_last_disbursement(self):
		for r in self:
			if r.disbursal_ids:
				r.last_disbursal_date = max(line.date for line in r.disbursal_ids)

	#Uses total expenditure to date (from the transactions object) and
	#total disbursed (from the disbursals object) to calculate the
	#amount in outstanding receipts
	@api.depends('total_expenditure', 'total_disbursed', 'bank_balance')
	def _get_outstanding_receipts(self):
		for r in self:
			r.outstanding_receipts = r.total_disbursed - r.bank_balance - r.total_expenditure

	@api.depends('outstanding_receipts', 'grant_amount')
	def _get_oustanding_receipt_dollars(self):
		for r in self:
			if r.outstanding_receipts and r.exchange_rate:
				r.outstanding_receipts_dollars = r.outstanding_receipts / r.exchange_rate

	#Counts the total amount spent by communities if the budget source is equal to Spark
	@api.multi
	@api.depends('transaction_ids', 'budget_line_item_ids')
	def _get_total_expenditure(self):
		for r in self:
			r.total_expenditure = sum(s.actual for s in r.budget_line_item_ids if s.source == "spark")


	#Calculates the remaining grant balance (total grant - total disbursed)
	@api.depends('total_disbursed', 'grant_amount_local')
	def _get_left_to_disburse(self):
		for r in self:
			r.left_to_disburse = r.grant_amount_local - r.total_disbursed

	#Counts the number of disbursals made to the community
	@api.multi
	@api.depends('disbursal_ids')
	def _get_number_disbursals(self):
		for r in self:
			r.number_disbursals = len(r.disbursal_ids)

	#Sums the amount disbursed to the community (in the disbursals object)
	@api.multi
	@api.depends('disbursal_ids')
	def _get_total_disbursed(self):
		for r in self:
			r.total_disbursed = sum(s.amount for s in r.disbursal_ids)

	#Concatenates the community number and name to come up with a project name
	@api.multi
	@api.depends('community_id', 'category_id')
	def _get_project_name(self):
		for r in self:
			if r.community_id and r.category_id:
				r.name = r.country_id.name + ': ' + r.community_number + ': ' + r.community_name + ': ' + r.category_id.name

	#Calculates the grant surplus (total grant - total budgeted) - relevant
	#for Standardized Grant Communities
	@api.depends('total', 'grant_amount_local')
	def _grant_surplus(self):
		for r in self:
			r.grant_surplus = r.grant_amount_local - r.spark_contribution

	#Counts the total budgeted
	@api.multi
	@api.depends('budget_line_item_ids')
	def _total(self):
		for r in self:
			r.total = sum(s.budgeted for s in r.budget_line_item_ids)

	#Counts the total amount budgeted for Spark to provide
	@api.multi
	@api.depends('budget_line_item_ids')
	def _spark_contribution(self):
		for r in self:
			r.spark_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "spark")

	@api.multi
	@api.depends('budget_line_item_ids')
	def _inkind_community_contribution(self):
		for r in self:
			r.inkind_community_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "community_in_kind")

	@api.multi
	@api.depends('budget_line_item_ids')
	def _cash_community_contribution(self):
		for r in self:
			r.cash_community_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "community_cash")

	#Counts the total amount budgeted for the Community to provide, including both inkind and cash
	@api.multi
	@api.depends('inkind_community_contribution', 'cash_community_contribution')
	def _community_contribution(self):
		for r in self:
			r.community_contribution = r.inkind_community_contribution + r.cash_community_contribution

	#Counts the total amount budgeted for another organization/government to provide
	@api.multi
	@api.depends('budget_line_item_ids')
	def _other_contribution(self):
		for r in self:
			r.other_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "other")

	#Counts the total amount budgeted for FVS-AMADE to provide
	@api.multi
	@api.depends('budget_line_item_ids')
	def _fvs_contribution(self):
		for r in self:
			r.fvs_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "FVS-AMADE")

	#Counts the percentage of the total project budget contributed by Spark
	@api.depends('spark_contribution', 'total')
	def _spark_contribution_percent(self):
		for r in self:
			if r.total>0:
				r.spark_contribution_percent = (r.spark_contribution / r.total) * 100

	#Counts the percentage of the total project budget contributed by the community
	@api.depends('community_contribution', 'total')
	def _community_contribution_percent(self):
		for r in self:
			if r.total >0:
				r.community_contribution_percent = (r.community_contribution / r.total) * 100

	#Counts the percentage of the total project budget contributed by FVS-AMADE
	@api.depends('fvs_contribution', 'total')
	def _fvs_contribution_percent(self):
		for r in self:
			if r.total >0:
				r.fvs_contribution_percent = (r.fvs_contribution / r.total) * 100
				
	#Counts the percentage of the total project budget contributed by another partner
	@api.depends('other_contribution', 'total')
	def _other_contribution_percent(self):
		for r in self:
			if r.total >0:
				r.other_contribution_percent = (r.other_contribution / r.total) * 100

	#Calculates the total grant amount in local currency using Spark's exchange rate
	@api.depends('grant_amount_local', 'exchange_rate')
	def _get_usd_grant_amount(self):
		for r in self:
			if r.exchange_rate>0:
				r.grant_amount = r.grant_amount_local / r.exchange_rate
Beispiel #3
0
class event_event(models.Model):
    """Event"""
    _name = 'event.event'
    _description = 'Event'
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _order = 'date_begin'

    name = fields.Char(string='Event Name',
                       translate=True,
                       required=True,
                       readonly=False,
                       states={'done': [('readonly', True)]})
    active = fields.Boolean(default=True, track_visibility="onchange")
    user_id = fields.Many2one('res.users',
                              string='Responsible',
                              default=lambda self: self.env.user,
                              readonly=False,
                              states={'done': [('readonly', True)]})
    company_id = fields.Many2one('res.company',
                                 string='Company',
                                 change_default=True,
                                 default=lambda self: self.env['res.company'].
                                 _company_default_get('event.event'),
                                 required=False,
                                 readonly=False,
                                 states={'done': [('readonly', True)]})
    organizer_id = fields.Many2one(
        'res.partner',
        string='Organizer',
        default=lambda self: self.env.user.company_id.partner_id)
    event_type_id = fields.Many2one('event.type',
                                    string='Category',
                                    readonly=False,
                                    states={'done': [('readonly', True)]},
                                    oldname='type')
    color = fields.Integer('Kanban Color Index')
    event_mail_ids = fields.One2many(
        'event.mail',
        'event_id',
        string='Mail Schedule',
        default=lambda self: self._default_event_mail_ids(),
        copy=True)

    @api.model
    def _default_event_mail_ids(self):
        return [(0, 0, {
            'interval_unit': 'now',
            'interval_type': 'after_sub',
            'template_id': self.env.ref('event.event_subscription')
        })]

    # Seats and computation
    seats_max = fields.Integer(
        string='Maximum Attendees Number',
        oldname='register_max',
        readonly=True,
        states={
            'draft': [('readonly', False)],
            'confirm': [('readonly', False)]
        },
        help=
        "For each event you can define a maximum registration of seats(number of attendees), above this numbers the registrations are not accepted."
    )
    seats_availability = fields.Selection([('limited', 'Limited'),
                                           ('unlimited', 'Unlimited')],
                                          'Maximum Attendees',
                                          required=True,
                                          default='unlimited')
    seats_min = fields.Integer(
        string='Minimum Attendees',
        oldname='register_min',
        help=
        "For each event you can define a minimum reserved seats (number of attendees), if it does not reach the mentioned registrations the event can not be confirmed (keep 0 to ignore this rule)"
    )
    seats_reserved = fields.Integer(oldname='register_current',
                                    string='Reserved Seats',
                                    store=True,
                                    readonly=True,
                                    compute='_compute_seats')
    seats_available = fields.Integer(oldname='register_avail',
                                     string='Maximum Attendees',
                                     store=True,
                                     readonly=True,
                                     compute='_compute_seats')
    seats_unconfirmed = fields.Integer(oldname='register_prospect',
                                       string='Unconfirmed Seat Reservations',
                                       store=True,
                                       readonly=True,
                                       compute='_compute_seats')
    seats_used = fields.Integer(oldname='register_attended',
                                string='Number of Participants',
                                store=True,
                                readonly=True,
                                compute='_compute_seats')
    seats_expected = fields.Integer(string='Number of Expected Attendees',
                                    readonly=True,
                                    compute='_compute_seats')

    @api.multi
    @api.depends('seats_max', 'registration_ids.state')
    def _compute_seats(self):
        """ Determine reserved, available, reserved but unconfirmed and used seats. """
        # initialize fields to 0
        for event in self:
            event.seats_unconfirmed = event.seats_reserved = event.seats_used = event.seats_available = 0
        # aggregate registrations by event and by state
        if self.ids:
            state_field = {
                'draft': 'seats_unconfirmed',
                'open': 'seats_reserved',
                'done': 'seats_used',
            }
            query = """ SELECT event_id, state, count(event_id)
                        FROM event_registration
                        WHERE event_id IN %s AND state IN ('draft', 'open', 'done')
                        GROUP BY event_id, state
                    """
            self._cr.execute(query, (tuple(self.ids), ))
            for event_id, state, num in self._cr.fetchall():
                event = self.browse(event_id)
                event[state_field[state]] += num
        # compute seats_available
        for event in self:
            if event.seats_max > 0:
                event.seats_available = event.seats_max - (
                    event.seats_reserved + event.seats_used)
            event.seats_expected = event.seats_unconfirmed + event.seats_reserved + event.seats_used

    # Registration fields
    registration_ids = fields.One2many('event.registration',
                                       'event_id',
                                       string='Attendees',
                                       readonly=False,
                                       states={'done': [('readonly', True)]})
    # Date fields
    date_tz = fields.Selection('_tz_get',
                               string='Timezone',
                               required=True,
                               default=lambda self: self.env.user.tz)
    date_begin = fields.Datetime(string='Start Date',
                                 required=True,
                                 track_visibility='onchange',
                                 states={'done': [('readonly', True)]})
    date_end = fields.Datetime(string='End Date',
                               required=True,
                               track_visibility='onchange',
                               states={'done': [('readonly', True)]})
    date_begin_located = fields.Datetime(string='Start Date Located',
                                         compute='_compute_date_begin_tz')
    date_end_located = fields.Datetime(string='End Date Located',
                                       compute='_compute_date_end_tz')

    @api.model
    def _tz_get(self):
        return [(x, x) for x in pytz.all_timezones]

    @api.one
    @api.depends('date_tz', 'date_begin')
    def _compute_date_begin_tz(self):
        if self.date_begin:
            self_in_tz = self.with_context(tz=(self.date_tz or 'UTC'))
            date_begin = fields.Datetime.from_string(self.date_begin)
            self.date_begin_located = fields.Datetime.to_string(
                fields.Datetime.context_timestamp(self_in_tz, date_begin))
        else:
            self.date_begin_located = False

    @api.one
    @api.depends('date_tz', 'date_end')
    def _compute_date_end_tz(self):
        if self.date_end:
            self_in_tz = self.with_context(tz=(self.date_tz or 'UTC'))
            date_end = fields.Datetime.from_string(self.date_end)
            self.date_end_located = fields.Datetime.to_string(
                fields.Datetime.context_timestamp(self_in_tz, date_end))
        else:
            self.date_end_located = False

    state = fields.Selection(
        [('draft', 'Unconfirmed'), ('cancel', 'Cancelled'),
         ('confirm', 'Confirmed'), ('done', 'Done')],
        string='Status',
        default='draft',
        readonly=True,
        required=True,
        copy=False,
        help=
        "If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'."
    )
    auto_confirm = fields.Boolean(string='Confirmation not required',
                                  compute='_compute_auto_confirm')

    @api.one
    def _compute_auto_confirm(self):
        self.auto_confirm = self.env['ir.values'].get_default(
            'event.config.settings', 'auto_confirmation')

    reply_to = fields.Char(
        'Reply-To Email',
        readonly=False,
        states={'done': [('readonly', True)]},
        help=
        "The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one."
    )
    address_id = fields.Many2one(
        'res.partner',
        string='Location',
        default=lambda self: self.env.user.company_id.partner_id,
        readonly=False,
        states={'done': [('readonly', True)]})
    country_id = fields.Many2one('res.country',
                                 'Country',
                                 related='address_id.country_id',
                                 store=True)
    description = fields.Html(string='Description',
                              oldname='note',
                              translate=True,
                              readonly=False,
                              states={'done': [('readonly', True)]})
    # badge fields
    badge_front = fields.Html(string='Badge Front')
    badge_back = fields.Html(string='Badge Back')
    badge_innerleft = fields.Html(string='Badge Inner Left')
    badge_innerright = fields.Html(string='Badge Inner Right')
    event_logo = fields.Html(string='Event Logo')

    @api.multi
    @api.depends('name', 'date_begin', 'date_end')
    def name_get(self):
        result = []
        for event in self:
            date_begin = fields.Datetime.from_string(event.date_begin)
            date_end = fields.Datetime.from_string(event.date_end)
            dates = [
                fields.Date.to_string(
                    fields.Datetime.context_timestamp(event, dt))
                for dt in [date_begin, date_end] if dt
            ]
            dates = sorted(set(dates))
            result.append(
                (event.id, '%s (%s)' % (event.name, ' - '.join(dates))))
        return result

    @api.one
    @api.constrains('seats_max', 'seats_available')
    def _check_seats_limit(self):
        if self.seats_availability == 'limited' and self.seats_max and self.seats_available < 0:
            raise ValidationError(_('No more available seats.'))

    @api.one
    @api.constrains('date_begin', 'date_end')
    def _check_closing_date(self):
        if self.date_end < self.date_begin:
            raise ValidationError(
                _('Closing Date cannot be set before Beginning Date.'))

    @api.model
    def create(self, vals):
        res = super(event_event, self).create(vals)
        if res.organizer_id:
            res.message_subscribe([res.organizer_id.id])
        if res.auto_confirm:
            res.button_confirm()
        return res

    @api.multi
    def write(self, vals):
        res = super(event_event, self).write(vals)
        if vals.get('organizer_id'):
            self.message_subscribe([vals['organizer_id']])
        return res

    @api.one
    def button_draft(self):
        self.state = 'draft'

    @api.one
    def button_cancel(self):
        for event_reg in self.registration_ids:
            if event_reg.state == 'done':
                raise UserError(
                    _("You have already set a registration for this event as 'Attended'. Please reset it to draft if you want to cancel this event."
                      ))
        self.registration_ids.write({'state': 'cancel'})
        self.state = 'cancel'

    @api.one
    def button_done(self):
        self.state = 'done'

    @api.one
    def button_confirm(self):
        self.state = 'confirm'

    @api.onchange('event_type_id')
    def _onchange_type(self):
        if self.event_type_id:
            self.seats_min = self.event_type_id.default_registration_min
            self.seats_max = self.event_type_id.default_registration_max
            self.reply_to = self.event_type_id.default_reply_to

    @api.multi
    def action_event_registration_report(self):
        res = self.env['ir.actions.act_window'].for_xml_id(
            'event', 'action_report_event_registration')
        res['context'] = {
            "search_default_event_id": self.id,
            "group_by": ['create_date:day'],
        }
        return res

    @api.one
    def mail_attendees(self,
                       template_id,
                       force_send=False,
                       filter_func=lambda self: True):
        for attendee in self.registration_ids.filtered(filter_func):
            self.env['mail.template'].browse(template_id).send_mail(
                attendee.id, force_send=force_send)
class AssetRegisterReport(models.TransientModel):
    _name = 'asset.register.report'
    _inherit = 'report.account.common'

    filter = fields.Selection(
        readonly=True,
        default='filter_date',
    )
    asset_status_ids = fields.Many2many(
        'account.asset.status',
        string='Asset Status',
    )
    asset_filter = fields.Text(
        string='Filter',
        help="More filter. You can use complex search with comma and between.",
    )
    asset_ids = fields.Many2many(
        'account.asset',
        string='Asset Code',
    )
    count_asset = fields.Integer(
        compute='_compute_count_asset',
        string='Asset Count',
    )
    asset_profile_ids = fields.Many2many(
        'account.asset.profile',
        string='Asset Profile',
        required=False,
    )
    responsible_person_ids = fields.Many2many(
        'res.users',
        string='Responsible Person',
    )
    building_ids = fields.Many2many(
        'res.building',
        string='Building',
    )
    floor_ids = fields.Many2many(
        'res.floor',
        string='Floor',
    )
    room_ids = fields.Many2many(
        'res.room',
        string='Room',
    )
    org_ids = fields.Many2many(
        'res.org',
        string='Org',
    )
    asset_state = fields.Many2many(
        'xlsx.report.status',
        string='Asset State',
        domain=[('location', '=', 'asset.register.view')],
        default=lambda self: self.env['xlsx.report.status'].search(
            [('location', '=', 'asset.register.view'),
             ('status', 'in', ['draft', 'open', 'close', 'removed'])]),
    )
    account_ids = fields.Many2many(
        'account.account',
        string='Account Code',
    )
    costcenter_ids = fields.Many2many(
        'res.costcenter',
        string='Cost Center',
    )
    division_ids = fields.Many2many(
        'res.division',
        string='Division',
    )
    sector_ids = fields.Many2many(
        'res.sector',
        string='Sector',
    )
    subsector_ids = fields.Many2many(
        'res.subsector',
        string='Subsector',
    )
    current_year = fields.Many2one(
        'account.fiscalyear',
        string='Current Year',
        default=lambda self: self._get_fiscalyear(),
    )
    # 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.")

    # More fileter
    budget_filter = fields.Text(
        string='Filter',
        help="More filter. You can use complex search with comma and between.",
    )
    budget = fields.Many2many(
        'chartfield.view',
        'asset_register_chartfield_rel',
        'wizard_id',
        'chartfield_id',
        string='Source Budget',
        domain=[('model', '!=', 'res.personnel.costcenter')],
    )
    count_budget = fields.Integer(
        compute='_compute_count_budget',
        string='Budget Count',
    )
    owner_budget_filter = fields.Text(
        string='Filter',
        help="More filter. You can use complex search with comma and between.",
    )
    owner_budget = fields.Many2many(
        'chartfield.view',
        'asset_register_owner_chartfield_rel',
        'wizard_id',
        'chartfield_id',
        string='Owner Budget',
        domain=[('model', '!=', 'res.personnel.costcenter')],
    )
    count_owner_budget = fields.Integer(
        compute='_compute_count_budget',
        string='Budget Count',
    )
    asset_active = fields.Selection(
        [('active', 'Active'), ('inactive', 'Inactive')],
        string='Asset Active',
        #default='active',
    )
    results = fields.Many2many(
        'asset.register.view',
        string='Results',
        compute='_compute_results',
        help='Use compute fields, so there is nothing store in database',
    )

    @api.multi
    @api.depends('asset_ids')
    def _compute_count_asset(self):
        for rec in self:
            rec.count_asset = len(rec.asset_ids)

    @api.multi
    @api.depends('budget', 'owner_budget')
    def _compute_count_budget(self):
        for rec in self:
            rec.count_budget = len(rec.budget)
            rec.count_owner_budget = len(rec.owner_budget)

    # @api.onchange('building_id')
    # def _onchange_building_id(self):
    #     self.floor_id = False
    #     self.room_id = False
    #
    # @api.onchange('floor_id')
    # def _onchange_floor_id(self):
    #     self.room_id = False

    @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 = []
        # Prepare DOM to filter assets
        if self.asset_filter:
            self._onchange_asset_filter()
        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 self.responsible_person_ids:
            dom += [('responsible_user_id', 'in',
                     tuple(self.responsible_person_ids.ids + [0]))]
        if self.org_ids:
            dom += [('owner_org_id', 'in', tuple(self.org_ids.ids + [0]))]
        if self.asset_status_ids:
            dom += [('status', 'in', tuple(self.asset_status_ids.ids + [0]))]
        if self.account_ids:
            dom += [('account_asset_id', 'in',
                     tuple(self.account_ids.ids + [0]))]
        if self.budget:
            dom_budget = \
                ["%s,%s" % ((x.model).encode('utf-8'), x.res_id)
                 for x in self.budget]
            dom += [('budget', 'in', tuple(dom_budget + ['0']))]
        if self.owner_budget:
            dom_owner = \
                ["%s,%s" % ((x.model).encode('utf-8'), x.res_id)
                 for x in self.owner_budget]
            dom += [('owner_budget', 'in', tuple(dom_owner + ['0']))]
        if self.costcenter_ids:
            dom += [('owner_costcenter_id', 'in',
                     tuple(self.costcenter_ids.ids + [0]))]
        if self.division_ids:
            dom += [('owner_division_id', 'in',
                     tuple(self.division_ids.ids + [0]))]
        if self.sector_ids:
            dom += [('owner_sector_id', 'in', tuple(self.sector_ids.ids + [0]))
                    ]
        if self.subsector_ids:
            dom += [('owner_subsector_id', 'in',
                     tuple(self.subsector_ids.ids + [0]))]
        if self.asset_state:
            res, state_name = [], self.asset_state
            for state in self.asset_state:
                state_name = self.env['xlsx.report.status'].search([
                    ('id', '=', state.id)
                ])
                res += [str(state_name.status)]
            if len(self.asset_state) == 1:
                dom += [('state', '=', str(state_name.status))]
            else:
                dom += [('state', 'in', tuple(res))]

        if self.building_ids:
            dom += [('building_id', 'in', tuple(self.building_ids.ids + [0]))]
        if self.floor_ids:
            dom += [('floor_id', 'in', tuple(self.floor_ids.ids + [0]))]
        if self.room_ids:
            dom += [('room_id', 'in', tuple(self.room_ids.ids + [0]))]
        if self.asset_active:
            if self.asset_active == 'active':
                dom += [('active', '=', True)]
            elif self.asset_active == 'inactive':
                dom += [('active', '=', False)]
        # date_start <= date_end
        if self.date_end:
            dom += [('date_start', '<=', self.date_end)]

        # Prepare fixed params
        date_start = False
        date_end = False

        if self.filter == 'filter_date':
            date_start = self.date_start  #self.fiscalyear_start_id.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 = 'where ' + where_str
        self._cr.execute(
            """
            select *
            from (
                select a.*, a.id asset_id, aap.account_asset_id,
                aa.code as account_code, aa.name as account_name,
                -- purchase_bf_current
                case when date_part('year', a.date_start+92) !=
                  CAST(%s AS int) then a.purchase_value
                 else null end as purchase_before_current,
                -- purchase_current
                case when date_part('year', a.date_start+92) =
                 CAST(%s AS int) then a.purchase_value
                 else null end as purchase_current,
                -- net_book_value
                (select a.purchase_value - 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) net_book_value,
                -- budget_type
                case when a.section_id is not null then 'Section'
                     when a.project_id is not null then 'Project'
                     when a.invest_asset_id is not null then 'Invest Asset'
                     when a.invest_construction_phase_id is not null
                        then 'Invest Construction Phase'
                    else null end as budget_type,
                -- budget
                case when a.section_id is not null then
                        concat('res.section,', a.section_id)
                     when a.project_id is not null then
                        concat('res.project,', a.project_id)
                     when a.invest_asset_id is not null then
                        concat('res.invest.asset,', a.invest_asset_id)
                     when a.invest_construction_phase_id is not null then
                        concat('res.invest.construction.phase,',
                               a.invest_construction_phase_id)
                     else null end as budget,
                -- owner_org_id
                case
                    when a.owner_section_id is not null then rs.org_id
                    when a.owner_project_id is not null then rp.org_id
                    when a.owner_invest_asset_id is not null then ria.org_id
                    when a.owner_invest_construction_phase_id is not null then ricp.org_id
                    else null
                end as owner_org_id,
                -- owner_budget
                case when a.owner_section_id is not null then
                        concat('res.section,', a.owner_section_id)
                     when a.owner_project_id is not null then
                        concat('res.project,', a.owner_project_id)
                     when a.owner_invest_asset_id is not null then
                        concat('res.invest.asset,', a.owner_invest_asset_id)
                     when a.owner_invest_construction_phase_id is not null
                        then concat('res.invest.construction.phase,',
                                     a.owner_invest_construction_phase_id)
                     else null end as owner_budget,
                -- owner_costcenter
                case when a.owner_section_id is not null then
                        rs.costcenter_id
                     when a.owner_project_id is not null then
                        rp.costcenter_id
                     when a.owner_invest_asset_id is not null then
                        ria.costcenter_id
                     when a.owner_invest_construction_phase_id is not null then
                        ricp.costcenter_id
                     else null end as owner_costcenter_id,
                -- owner_division
                case when a.owner_section_id is not null then
                        rs.division_id
                     else null end as owner_division_id,
                -- owner_sector
                case when a.owner_section_id is not null then
                        rs.sector_id
                     else null end as owner_sector_id,
                -- owner_subsector
                case when a.owner_section_id is not null then
                        rs.subsector_id
                     else null end as owner_subsector_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
                (select coalesce(sum(credit-debit), 0.0)
                 from account_move_line ml
                 where account_id in %s  -- accumulatedp account
                 and ml.date < %s -- date start
                 and asset_id = a.id) accumulated_bf
            from
            account_asset a
            left join account_asset_profile aap on a.profile_id = aap.id
            left join res_section rs on a.owner_section_id = rs.id
            left join res_project rp on a.owner_project_id = rp.id
            left join res_invest_asset ria on a.owner_invest_asset_id = ria.id
            left join res_invest_construction_phase ricp on
            a.owner_invest_construction_phase_id = ricp.id
            left join account_account aa on aap.account_asset_id = aa.id
            ) asset
        """ + where_str + 'order by asset.account_code, asset.code',
            (self.fiscalyear_start_id.name, self.fiscalyear_start_id.name,
             tuple(accum_depre_account_ids), date_end,
             tuple(depre_account_ids), date_start, date_end,
             tuple(accum_depre_account_ids), date_end,
             tuple(accum_depre_account_ids), date_start))

        results = self._cr.dictfetchall()
        ReportLine = self.env['asset.register.view']
        self.results = [ReportLine.new(line).id for line in results]
        return True

    # @api.multi
    # def action_get_report(self):
    #     action = self.env.ref(
    #         'pabi_account_report.action_asset_register_report_form')
    #     return super(AssetRegisterReport, self).action_get_report()

    @api.onchange('asset_filter')
    def _onchange_asset_filter(self):
        self.asset_ids = []
        Asset = self.env['account.asset']
        dom = []
        if self.asset_filter:
            codes = self.asset_filter.split('\n')
            codes = [x.strip() for x in codes]
            codes = ','.join(codes)
            dom.append(('code', 'ilike', codes))
            self.asset_ids = Asset.with_context(active_test=False).search(
                dom, order='id')

    @api.onchange('budget_filter')
    def _onchange_budget_filter(self):
        self.budget = []
        Chartfield = self.env['chartfield.view']
        dom = []
        if self.budget_filter:
            codes = self.budget_filter.split('\n')
            codes = [x.strip() for x in codes]
            codes = ','.join(codes)
            dom.append(('code', 'ilike', codes))
            self.budget = Chartfield.search(dom, order='id')

    @api.onchange('owner_budget_filter')
    def _onchange_owner_budget_filter(self):
        self.budget = []
        Chartfield = self.env['chartfield.view']
        dom = []
        if self.owner_budget_filter:
            codes = self.owner_budget_filter.split('\n')
            codes = [x.strip() for x in codes]
            codes = ','.join(codes)
            dom.append(('code', 'ilike', codes))
            self.owner_budget = Chartfield.search(dom, order='id')

    @api.onchange('asset_state', 'asset_active')
    def _onchange_asset_state_asset_active(self):
        res = {}
        state_list = []
        for rec in self.asset_state:
            status = rec.status
            state_list.append(status)
        if self.asset_active == 'active':
            res['domain'] = {
                'asset_ids': [('state', 'in', state_list),
                              ('active', '=', True)]
            }
        if self.asset_active == 'inactive':
            res['domain'] = {
                'asset_ids': [('state', 'in', state_list),
                              ('active', '=', False)]
            }
        return res

    @api.onchange('costcenter_ids')
    def _onchange_costcenter(self):
        res = {}
        costcenter_list = []
        for rec in self.costcenter_ids:
            code = rec.code
            costcenter_list.append(code)
        if self.costcenter_ids:
            res['domain'] = {
                'budget': [('code', 'in', costcenter_list)],
                'owner_budget': [('code', 'in', costcenter_list)]
            }
        else:
            res['domain'] = {
                'budget': [('active', '=', True)],
                'owner_budget': [('active', '=', True)]
            }
        return res
Beispiel #5
0
class mail_message(models.Model):
    _inherit = 'mail.message'

    is_moved = fields.Boolean('Is moved')
    moved_from_res_id = fields.Integer('Related Document ID (Original)')
    moved_from_model = fields.Char('Related Document Model (Original)')
    moved_from_parent_id = fields.Many2one('mail.message',
                                           'Parent Message (Original)',
                                           ondelete='set null')
    moved_by_message_id = fields.Many2one(
        'mail.message',
        'Moved by message',
        ondelete='set null',
        help='Top message, that initate moving this message')
    moved_by_user_id = fields.Many2one('res.users',
                                       'Moved by user',
                                       ondelete='set null')
    all_child_ids = fields.One2many('mail.message',
                                    string='All childs',
                                    compute='_get_all_childs',
                                    help='all childs, including subchilds')

    @api.one
    def _get_all_childs(self, include_myself=True):
        ids = []
        if include_myself:
            ids.append(self.id)
        while True:
            new_ids = self.search([('parent_id', 'in', ids),
                                   ('id', 'not in', ids)]).ids
            if new_ids:
                ids = ids + new_ids
                continue
            break
        moved_childs = self.search([('moved_by_message_id', '=', self.id)]).ids
        self.all_child_ids = ids + moved_childs

    @api.one
    def move(self, parent_id, res_id, model, move_back):
        vals = {}
        if move_back:
            # clear variables if we move everything back
            vals['is_moved'] = False
            vals['moved_by_user_id'] = None
            vals['moved_by_message_id'] = None

            vals['moved_from_res_id'] = None
            vals['moved_from_model'] = None
            vals['moved_from_parent_id'] = None
        else:
            vals['parent_id'] = parent_id
            vals['res_id'] = res_id
            vals['model'] = model

            vals['is_moved'] = True
            vals['moved_by_user_id'] = self.env.user.id
            vals['moved_by_message_id'] = self.id

        for r in self.all_child_ids:
            r_vals = vals.copy()
            if not r.is_moved:
                # moved_from_* variables contain not last, but original
                # reference
                r_vals['moved_from_parent_id'] = r.parent_id.id
                r_vals['moved_from_res_id'] = r.res_id
                r_vals['moved_from_model'] = r.model
            elif move_back:
                r_vals['parent_id'] = r.moved_from_parent_id.id
                r_vals['res_id'] = r.moved_from_res_id
                r_vals['model'] = r.moved_from_model
            print 'update message', r, r_vals
            r.sudo().write(r_vals)

    def name_get(self, cr, uid, ids, context=None):
        if not (context or {}).get('extended_name'):
            return super(mail_message, self).name_get(cr,
                                                      uid,
                                                      ids,
                                                      context=context)
        if isinstance(ids, (list, tuple)) and not len(ids):
            return []
        if isinstance(ids, (long, int)):
            ids = [ids]
        reads = self.read(cr,
                          uid,
                          ids, ['record_name', 'model', 'res_id'],
                          context=context)
        res = []
        for record in reads:
            name = record['record_name'] or ''
            extended_name = '   [%s] ID %s' % (record.get(
                'model', 'UNDEF'), record.get('res_id', 'UNDEF'))
            res.append((record['id'], name + extended_name))
        return res

    def _message_read_dict(self,
                           cr,
                           uid,
                           message,
                           parent_id=False,
                           context=None):
        res = super(mail_message,
                    self)._message_read_dict(cr, uid, message, parent_id,
                                             context)
        res['is_moved'] = message.is_moved
        return res
Beispiel #6
0
class MgmtSystemAction(models.Model):
    """Model class that manage action."""

    _name = "mgmtsystem.action"
    _description = "Action"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    def _default_company(self):
        """Return the user company id."""
        return self.env.user.company_id

    def _default_owner(self):
        """Return the user."""
        return self.env.user

    def _default_stage(self):
        """Return the default stage."""
        return self.env['mgmtsystem.action.stage'].search(
            [('is_starting', '=', True)], limit=1)

    @api.model
    def _elapsed_days(self, dt1_text, dt2_text):
        res = 0
        if dt1_text and dt2_text:
            dt1 = fields.Datetime.from_string(dt1_text)
            dt2 = fields.Datetime.from_string(dt2_text)
            res = (dt2 - dt1).days
        return res

    @api.depends('opening_date', 'create_date')
    def _compute_number_of_days_to_open(self):
        for action in self:
            action.number_of_days_to_close_open = action._elapsed_days(
                action.create_date, action.opening_date)

    @api.depends('date_closed', 'create_date')
    def _compute_number_of_days_to_close(self):
        for action in self:
            action.number_of_days_to_close_open = action._elapsed_days(
                action.create_date, action.date_closed)

    name = fields.Char('Subject', required=True)
    active = fields.Boolean('Active', default=True)
    date_deadline = fields.Date('Deadline')

    create_date = fields.Datetime('Create Date',
                                  readonly=True,
                                  default=fields.datetime.now())
    cancel_date = fields.Datetime('Cancel Date', readonly=True)
    opening_date = fields.Datetime('Opening Date', readonly=True)
    date_closed = fields.Datetime('Closed Date', readonly=True)
    number_of_days_to_open = fields.Integer(
        '# of days to open',
        compute=_compute_number_of_days_to_open,
        store=True)
    number_of_days_to_close = fields.Integer(
        '# of days to close',
        compute=_compute_number_of_days_to_close,
        store=True)
    reference = fields.Char('Reference',
                            required=True,
                            readonly=True,
                            default="NEW")
    user_id = fields.Many2one('res.users',
                              'Responsible',
                              default=_default_owner,
                              required=True)
    description = fields.Text('Description')
    type_action = fields.Selection(
        [('immediate', 'Immediate Action'),
         ('correction', 'Corrective Action'),
         ('prevention', 'Preventive Action'),
         ('improvement', 'Improvement Opportunity')],
        'Response Type',
        required=True)

    system_id = fields.Many2one('mgmtsystem.system', 'System')
    company_id = fields.Many2one('res.company',
                                 'Company',
                                 default=_default_company)
    stage_id = fields.Many2one('mgmtsystem.action.stage',
                               'Stage',
                               default=_default_stage)

    @api.model
    def _stage_groups(self, present_ids, domain, **kwargs):
        """This method is used by Kanban view to show empty stages."""
        # perform search
        # We search here only stage ids
        stage_ids = self.env['mgmtsystem.action.stage']._search([])
        # We search here stages objects
        result = self.env['mgmtsystem.action.stage'].search([]).name_get()
        # restore order of the search
        result.sort(
            lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
        return result, None

    _group_by_full = {'stage_id': _stage_groups}

    @api.model
    def _get_stage_new(self):
        return self.env['mgmtsystem.action.stage'].search(
            [('is_starting', '=', True)], limit=1)

    @api.model
    def _get_stage_open(self):
        return self.env.ref('mgmtsystem_action.stage_open')

    @api.model
    def _get_stage_close(self):
        return self.env.ref('mgmtsystem_action.stage_close')

    @api.model
    def _get_stage_cancel(self):
        return self.env.ref('mgmtsystem_action.stage_cancel')

    @api.multi
    def case_open(self):
        """ Opens case """
        for case in self:
            case.write({'active': True, 'stage_id': case._get_stage_open().id})
        return True
Beispiel #7
0
class TestScriptSetupActionOperation(models.Model):
    _name = "hc.test.script.setup.action.operation"
    _description = "Test Script Setup Action Operation"

    setup_action_id = fields.Many2one(
        comodel_name="hc.test.script.setup.action",
        string="Setup Action",
        help=
        "Setup Action associated with this Test Script Setup Action Operation."
    )
    test_action_id = fields.Many2one(
        comodel_name="hc.test.script.test.action",
        string="Test Action",
        help=
        "Test Action associated with this Test Script Setup Action Operation.")
    teardown_action_id = fields.Many2one(
        comodel_name="hc.test.script.teardown.action",
        string="Teardown Action",
        help=
        "Teardown Action associated with this Test Script Setup Action Operation."
    )
    type_id = fields.Many2one(
        comodel_name="hc.vs.test.script.operation.code",
        string="Type",
        help="The operation code type that will be executed.")
    resource_id = fields.Many2one(comodel_name="hc.vs.defined.type",
                                  string="Resource",
                                  help="Resource type.")
    label = fields.Char(string="Label",
                        help="Tracking/logging operation label.")
    description = fields.Text(string="Description",
                              help="Tracking/reporting operation description.")
    accept = fields.Selection(
        string="Operation Accept",
        selection=[("xml", "XML"), ("json", "JSON"), ("ttl", "TTL"),
                   ("none", "None")],
        help=
        "The content-type or mime-type to use for RESTful operation in the 'Accept' header."
    )
    content_type = fields.Selection(
        string="Operation Content Type",
        selection=[("xml", "XML"), ("json", "JSON"), ("ttl", "TTL"),
                   ("none", "None")],
        help=
        "The content-type or mime-type to use for RESTful operation in the 'Content-Type' header."
    )
    destination = fields.Integer(string="Destination",
                                 help="Server responding to the request.")
    is_encode_request_url = fields.Boolean(
        string="Encode Request URL",
        help="Whether or not to send the request url in encoded format.")
    origin = fields.Integer(string="Origin",
                            help="Server initiating the request.")
    params = fields.Char(string="Params",
                         help="Explicitly defined path parameters.")
    request_id = fields.Char(string="Request Id",
                             help="Fixture Id of mapped request.")
    response_id = fields.Char(string="Response Id",
                              help="Fixture Id of mapped response.")
    source_id = fields.Char(
        string="Source Id",
        help="Fixture Id of body for PUT and POST requests.")
    target_id = fields.Char(
        string="Target Id",
        help=
        "Id of fixture used for extracting the [id], [type], and [vid] for GET requests."
    )
    url = fields.Char(string="URL", help="Request URL.")
    request_header_ids = fields.One2many(
        comodel_name="hc.test.script.setup.action.operation.request.header",
        inverse_name="operation_id",
        string="Request Headers",
        help="Each operation can have one ore more header elements.")
Beispiel #8
0
class HrEmployee(models.Model):
    _inherit = 'hr.employee'


    # def _get_chargefam(self, cr, uid, ids, field_name, arg, context):
    #     employees = self.browse(cr, uid, ids)
    #     res = {}
    #     for employee in employees:
    #         count = 0
    #         for child in employee.children_ids:
    #             ages = child.age.split()
    #             if len(ages) > 1:
    #                 if int(ages[0][:-1]) < 21:
    #                     count += 1
    #         res[employee.id] = count
    #     return res

    @api.multi
    def _get_chargefam(self):
        for emp in self:
            ages_list = emp.mapped('children_ids.age')
            emp.chargefam = sum(int(age.split('a')[0]) < 21 for age in ages_list)

    @api.multi
    def _get_visibility(self):
        user_obj = self.env['res.users']
        for emp in self:
            uid = self._uid
            visible = False
            group_ids = user_obj.browse(uid).groups_id
            group_user_id_user = self.env.ref('base.group_hr_user')
            group_user_id_manager = self.env.ref('base.group_hr_manager')
            if (group_user_id_user.id in [group.id for group in group_ids]) or (group_user_id_manager.id in [group.id for group in group_ids]) \
               or (emp.user_id.id == uid) or (emp.parent_id.user_id.id == uid):
                visible = True
            emp.visible = visible

    @api.multi
    def _wb(self):
        for emp in self:
            if emp.birthday:
                emp.weekbirthday = datetime.datetime.strptime(emp.birthday, "%Y-%m-%d").strftime("%W")

    # TODO
    def attendance_action_change(self, cr, uid, ids, context=None):
        if not context:
            return {}
        return False

    @api.multi
    def _get_children(self):
        """
            Get number of all children for an employee
        """
        for emp in self:
            emp.children = len(emp.children_ids)

    matricule = fields.Char(string='Matricule', size=64)
    cin = fields.Char(string='CIN', size=64)
    cin_date = fields.Date(string='Date CIN')
    cin_place = fields.Char(string='Lieu CIN', size=30)
    chargefam = fields.Float(string='Charge Familliale', compute='_get_chargefam')
    visible = fields.Boolean(string='Visible',compute='_get_visibility')
    payment_term_id = fields.One2many(string='Mode de Paiement',comodel_name='payment.term',inverse_name='employee_id')
    anciennete = fields.Boolean(string='Prime anciennete',help=u'Est ce que cet employe benificie de la prime d\'anciennete')
    affilie = fields.Boolean(string='Affilie',help=u'Est ce qu\'on va calculer les cotisations pour cet employe')
    state = fields.Selection(string='State', selection=[('absent', 'Absent'), ('present', 'Present')], default='absent')
    children_ids = fields.One2many(string='Enfants', comodel_name='hr.employee.children', inverse_name='employee_id')
    mother = fields.Char(string='Mere', size=64)
    father = fields.Char(string='Pere', size=64)
    spouse = fields.Char(string='Epoux(se)', size=64)
    weekbirthday = fields.Char(string='Week Birthday', compute='_wb')
    sanction_ids = fields.One2many(string='Sanctions', comodel_name='hr.employee.sanction', inverse_name='name')
    qualification_ids = fields.One2many(string='Qualifications', comodel_name='hr.employee.qualification', inverse_name='employee_id')
    medical_ids = fields.One2many(string='Billet Medical', comodel_name='hr.employee.medical.ticket', inverse_name='employee_id')
    decoration_ids = fields.One2many(string='Decorations', comodel_name='hr.employee.decoration', inverse_name='employee_id')
    note_ids = fields.One2many(string='Note Employe', comodel_name='hr.employee.note', inverse_name='employee_id')
    lastjob_ids = fields.One2many(string='Ancien Emploie', comodel_name='hr.employee.last.job', inverse_name='employee_id')
    formation_ids = fields.One2many(string='Formation', comodel_name='hr.employee.formation', inverse_name='employee_id')
    aptitude_ids = fields.One2many(string='Aptitudes', comodel_name='hr.employee.aptitude', inverse_name='employee_id')
    #contract_ids = fields.One2many(string='Contrats',comodel_name='hr.contract',inverse_name='employee_id')
    children = fields.Integer(string=u'Number of childs',compute='_get_children')
Beispiel #9
0
class CenitDataTypeTrigger(models.Model):
    _name = "cenit.data_type.trigger"

    data_type = fields.Many2one("cenit.data_type", "Data Type")
    name = fields.Selection([
        ("on_create", "On creation"),
        ("on_write", "On update"),
        ("on_create_or_write", "On creation or update"),
        ("interval", "On interval"),
        ("only_manual", "Only manually"),
    ],
                            required=True)

    cron = fields.Many2one('ir.cron', string='Cron rules')
    cron_lapse = fields.Integer("Interval number", default=10)
    cron_units = fields.Selection([('minutes', 'Minutes'), ('hours', 'Hours'),
                                   ('work_days', 'Work Days'),
                                   ('days', 'Days'), ('weeks', 'Weeks'),
                                   ('months', 'Months')],
                                  string="Interval units",
                                  default='minutes')
    cron_restrictions = fields.Selection([("create", "Newly created"),
                                          ("update", "Newly updated"),
                                          ("all", "All")],
                                         string="Restrictions",
                                         default="all")
    base_action_rules = fields.Many2many('base.action.rule',
                                         string='Action Rules')

    last_execution = fields.Datetime()

    @api.one
    def unlink(self):
        if self.cron:
            self.cron.unlink()
        if self.base_action_rules:
            for bar in self.base_action_rules:
                bar.server_action_ids.unlink()
            self.base_action_rules.unlink()

        return super(CenitDataTypeTrigger, self).unlink()

    @api.one
    def sync(self):
        if not self.data_type.enabled:
            if self.cron:
                self.cron.unlink()
            if self.base_action_rules:
                for bar in self.base_action_rules:
                    bar.server_action_ids.unlink()
                self.base_action_rules.unlink()

        if self.name == 'only_manual':

            if self.base_action_rules:
                for bar in self.base_action_rules:
                    bar.server_action_ids.unlink()
                self.base_action_rules.unlink()

            elif self.cron:
                self.cron.unlink()

        if self.name == 'interval':
            ic_obj = self.env['ir.cron']

            if self.cron:
                vals_ic = {
                    'name':
                    'send_%s_%s' %
                    (self.cron_restrictions, self.data_type.model.model),
                    'interval_number':
                    self.cron_lapse,
                    'interval_type':
                    self.cron_units,
                }
                _logger.info("\n\nWRITE IC: %s\n", vals_ic)
                self.cron.write(vals_ic)
            else:
                vals_ic = {
                    'name':
                    'send_%s_%s' %
                    (self.cron_restrictions, self.data_type.model.model),
                    'interval_number':
                    self.cron_lapse,
                    'interval_type':
                    self.cron_units,
                    'numbercall':
                    -1,
                    'model':
                    'cenit.data_type',
                    'function':
                    'perform_scheduled_action',
                    'args':
                    '(%s,)' % str(self.data_type.id)
                }
                _logger.info("\n\nCREATE IC: %s\n", vals_ic)
                ic = ic_obj.create(vals_ic)
                self.with_context(local=True).write({'cron': ic.id})

            if self.base_action_rules:
                for bar in self.base_action_rules:
                    bar.server_action_ids.unlink()
                self.base_action_rules.unlink()

        elif self.name in ('on_create', 'on_write', 'on_create_or_write'):
            ias_obj = self.env['ir.actions.server']
            bar_obj = self.env['base.action.rule']

            if self.base_action_rules:
                for bar in self.base_action_rules:
                    bar.server_action_ids.unlink()
                self.base_action_rules.unlink()

            rules = []
            action_name = 'send_one_%s_as_%s' % (self.data_type.model.model,
                                                 self.data_type.cenit_root)
            cd = "self.pool.get('{}').browse(cr, uid, {}).trigger_flows(obj)".format(
                self.data_type._name, self.data_type.id)
            vals_ias = {
                'name': action_name,
                'model_id': self.data_type.model.id,
                'state': 'code',
                'code': cd
            }
            ias = ias_obj.create(vals_ias)
            vals_bar = {
                'name': action_name,
                'active': True,
                'kind': self.name,
                'model_id': self.data_type.model.id,
                'server_action_ids': [(6, False, [ias.id])]
            }
            bar = bar_obj.create(vals_bar)
            rules.append((4, bar.id, False))

            self.with_context(local=True).write({'base_action_rules': rules})

            if self.cron:
                self.cron.unlink()

        return True
Beispiel #10
0
class AccountTaxGroup(models.Model):
    _name = 'account.tax.group'
    _order = 'sequence asc'

    name = fields.Char(required=True, translate=True)
    sequence = fields.Integer(default=10)
Beispiel #11
0
class AccountTax(models.Model):
    _name = 'account.tax'
    _description = 'Tax'
    _order = 'sequence'

    @api.model
    def _default_tax_group(self):
        return self.env['account.tax.group'].search([], limit=1)

    name = fields.Char(string='Tax Name', required=True, translate=True)
    type_tax_use = fields.Selection([('sale', 'Sales'), ('purchase', 'Purchases'), ('none', 'None')], string='Tax Scope', required=True, default="sale",
        help="Determines where the tax is selectable. Note : 'None' means a tax can't be used by itself, however it can still be used in a group.")
    amount_type = fields.Selection(default='percent', string="Tax Computation", required=True, oldname='type',
        selection=[('group', 'Group of Taxes'), ('fixed', 'Fixed'), ('percent', 'Percentage of Price'), ('division', 'Percentage of Price Tax Included')])
    active = fields.Boolean(default=True, help="Set active to false to hide the tax without removing it.")
    company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.user.company_id)
    children_tax_ids = fields.Many2many('account.tax', 'account_tax_filiation_rel', 'parent_tax', 'child_tax', string='Children Taxes')
    sequence = fields.Integer(required=True, default=1,
        help="The sequence field is used to define order in which the tax lines are applied.")
    amount = fields.Float(required=True, digits=(16, 4))
    account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)], string='Tax Account', ondelete='restrict',
        help="Account that will be set on invoice tax lines for invoices. Leave empty to use the expense account.", oldname='account_collected_id')
    refund_account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)], string='Tax Account on Refunds', ondelete='restrict',
        help="Account that will be set on invoice tax lines for refunds. Leave empty to use the expense account.", oldname='account_paid_id')
    description = fields.Char(string='Label on Invoices', translate=True)
    price_include = fields.Boolean(string='Included in Price', default=False,
        help="Check this if the price you use on the product and invoices includes this tax.")
    include_base_amount = fields.Boolean(string='Affect Base of Subsequent Taxes', default=False,
        help="If set, taxes which are computed after this one will be computed based on the price tax included.")
    analytic = fields.Boolean(string="Include in Analytic Cost", help="If set, the amount computed by this tax will be assigned to the same analytic account as the invoice line (if any)")
    tag_ids = fields.Many2many('account.account.tag', 'account_tax_account_tag', string='Tags', help="Optional tags you may want to assign for custom reporting")
    tax_group_id = fields.Many2one('account.tax.group', string="Tax Group", default=_default_tax_group, required=True)

    _sql_constraints = [
        ('name_company_uniq', 'unique(name, company_id, type_tax_use)', 'Tax names must be unique !'),
    ]

    @api.multi
    def unlink(self):
        company_id = self.env.user.company_id.id
        ir_values = self.env['ir.values']
        supplier_taxes_id = set(ir_values.get_default('product.template', 'supplier_taxes_id', company_id=company_id))
        deleted_sup_tax = self.filtered(lambda tax: tax.id in supplier_taxes_id)
        if deleted_sup_tax:
            ir_values.sudo().set_default('product.template', "supplier_taxes_id", list(supplier_taxes_id - set(deleted_sup_tax.ids)), for_all_users=True, company_id=company_id)
        taxes_id = set(self.env['ir.values'].get_default('product.template', 'taxes_id', company_id=company_id))
        deleted_tax = self.filtered(lambda tax: tax.id in taxes_id)
        if deleted_tax:
            ir_values.sudo().set_default('product.template', "taxes_id", list(taxes_id - set(deleted_tax.ids)), for_all_users=True, company_id=company_id)
        return super(AccountTax, self).unlink()

    @api.one
    @api.constrains('children_tax_ids', 'type_tax_use')
    def _check_children_scope(self):
        if not all(child.type_tax_use in ('none', self.type_tax_use) for child in self.children_tax_ids):
            raise UserError(_('The application scope of taxes in a group must be either the same as the group or "None".'))

    @api.one
    def copy(self, default=None):
        default = dict(default or {}, name=_("%s (Copy)") % self.name)
        return super(AccountTax, self).copy(default=default)

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=80):
        """ Returns a list of tupples containing id, name, as internally it is called {def name_get}
            result format: {[(id, name), (id, name), ...]}
        """
        args = args or []
        if operator in expression.NEGATIVE_TERM_OPERATORS:
            domain = [('description', operator, name), ('name', operator, name)]
        else:
            domain = ['|', ('description', operator, name), ('name', operator, name)]
        taxes = self.search(expression.AND([domain, args]), limit=limit)
        return taxes.name_get()

    @api.model
    def search(self, args, offset=0, limit=None, order=None, count=False):
        context = self._context or {}

        if context.get('type'):
            if context.get('type') in ('out_invoice', 'out_refund'):
                args += [('type_tax_use', '=', 'sale')]
            elif context.get('type') in ('in_invoice', 'in_refund'):
                args += [('type_tax_use', '=', 'purchase')]

        if context.get('journal_id'):
            journal = self.env['account.journal'].browse(context.get('journal_id'))
            if journal.type in ('sale', 'purchase'):
                args += [('type_tax_use', '=', journal.type)]

        return super(AccountTax, self).search(args, offset, limit, order, count=count)

    @api.onchange('amount')
    def onchange_amount(self):
        if self.amount_type in ('percent', 'division') and self.amount != 0.0 and not self.description:
            self.description = "{0:.4g}%".format(self.amount)

    @api.onchange('account_id')
    def onchange_account_id(self):
        self.refund_account_id = self.account_id

    @api.onchange('price_include')
    def onchange_price_include(self):
        if self.price_include:
            self.include_base_amount = True

    def _compute_amount(self, base_amount, price_unit, quantity=1.0, product=None, partner=None):
        """ Returns the amount of a single tax. base_amount is the actual amount on which the tax is applied, which is
            price_unit * quantity eventually affected by previous taxes (if tax is include_base_amount XOR price_include)
        """
        self.ensure_one()
        if self.amount_type == 'fixed':
            return math.copysign(self.amount, base_amount) * quantity
        if (self.amount_type == 'percent' and not self.price_include) or (self.amount_type == 'division' and self.price_include):
            return base_amount * self.amount / 100
        if self.amount_type == 'percent' and self.price_include:
            return base_amount - (base_amount / (1 + self.amount / 100))
        if self.amount_type == 'division' and not self.price_include:
            return base_amount / (1 - self.amount / 100) - base_amount

    @api.v8
    def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None):
        """ Returns all information required to apply taxes (in self + their children in case of a tax goup).
            We consider the sequence of the parent for group of taxes.
                Eg. considering letters as taxes and alphabetic order as sequence :
                [G, B([A, D, F]), E, C] will be computed as [A, D, F, C, E, G]

        RETURN: {
            'total_excluded': 0.0,    # Total without taxes
            'total_included': 0.0,    # Total with taxes
            'taxes': [{               # One dict for each tax in self and their children
                'id': int,
                'name': str,
                'amount': float,
                'sequence': int,
                'account_id': int,
                'refund_account_id': int,
                'analytic': boolean,
            }]
        } """
        if len(self) == 0:
            company_id = self.env.user.company_id
        else:
            company_id = self[0].company_id
        if not currency:
            currency = company_id.currency_id
        taxes = []
        # By default, for each tax, tax amount will first be computed
        # and rounded at the 'Account' decimal precision for each
        # PO/SO/invoice line and then these rounded amounts will be
        # summed, leading to the total amount for that tax. But, if the
        # company has tax_calculation_rounding_method = round_globally,
        # we still follow the same method, but we use a much larger
        # precision when we round the tax amount for each line (we use
        # the 'Account' decimal precision + 5), and that way it's like
        # rounding after the sum of the tax amounts of each line
        prec = currency.decimal_places
        if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
            prec += 5
        total_excluded = total_included = base = round(price_unit * quantity, prec)

        # Sorting key is mandatory in this case. When no key is provided, sorted() will perform a
        # search. However, the search method is overridden in account.tax in order to add a domain
        # depending on the context. This domain might filter out some taxes from self, e.g. in the
        # case of group taxes.
        for tax in self.sorted(key=lambda r: r.sequence):
            if tax.amount_type == 'group':
                ret = tax.children_tax_ids.compute_all(price_unit, currency, quantity, product, partner)
                total_excluded = ret['total_excluded']
                base = ret['base']
                total_included = ret['total_included']
                tax_amount = total_included - total_excluded
                taxes += ret['taxes']
                continue

            tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
            if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
                tax_amount = round(tax_amount, prec)
            else:
                tax_amount = currency.round(tax_amount)

            if tax.price_include:
                total_excluded -= tax_amount
                base -= tax_amount
            else:
                total_included += tax_amount

            if tax.include_base_amount:
                base += tax_amount

            taxes.append({
                'id': tax.id,
                'name': tax.with_context(**{'lang': partner.lang} if partner else {}).name,
                'amount': tax_amount,
                'sequence': tax.sequence,
                'account_id': tax.account_id.id,
                'refund_account_id': tax.refund_account_id.id,
                'analytic': tax.analytic,
            })

        return {
            'taxes': sorted(taxes, key=lambda k: k['sequence']),
            'total_excluded': currency.round(total_excluded) if bool(self.env.context.get("round", True)) else total_excluded,
            'total_included': currency.round(total_included) if bool(self.env.context.get("round", True)) else total_included,
            'base': base,
        }

    @api.v7
    def compute_all(self, cr, uid, ids, price_unit, currency_id=None, quantity=1.0, product_id=None, partner_id=None, context=None):
        currency = currency_id and self.pool.get('res.currency').browse(cr, uid, currency_id, context=context) or None
        product = product_id and self.pool.get('product.product').browse(cr, uid, product_id, context=context) or None
        partner = partner_id and self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) or None
        ids = isinstance(ids, (int, long)) and [ids] or ids
        recs = self.browse(cr, uid, ids, context=context)
        return AccountTax.compute_all(recs, price_unit, currency, quantity, product, partner)

    @api.model
    def _fix_tax_included_price(self, price, prod_taxes, line_taxes):
        """Subtract tax amount from price when corresponding "price included" taxes do not apply"""
        # FIXME get currency in param?
        incl_tax = prod_taxes.filtered(lambda tax: tax not in line_taxes and tax.price_include)
        if incl_tax:
            return incl_tax.compute_all(price)['total_excluded']
        return price
Beispiel #12
0
class AccountJournal(models.Model):
    _name = "account.journal"
    _description = "Journal"
    _order = 'sequence, type, code'

    def _default_inbound_payment_methods(self):
        return self.env.ref('account.account_payment_method_manual_in')

    def _default_outbound_payment_methods(self):
        return self.env.ref('account.account_payment_method_manual_out')

    name = fields.Char(string='Journal Name', required=True)
    code = fields.Char(string='Short Code', size=5, required=True, help="The journal entries of this journal will be named using this prefix.")
    type = fields.Selection([
            ('sale', 'Sale'),
            ('purchase', 'Purchase'),
            ('cash', 'Cash'),
            ('bank', 'Bank'),
            ('general', 'Miscellaneous'),
        ], required=True,
        help="Select 'Sale' for customer invoices journals."\
        " Select 'Purchase' for vendor bills journals."\
        " Select 'Cash' or 'Bank' for journals that are used in customer or vendor payments."\
        " Select 'General' for miscellaneous operations journals."\
        " Select 'Opening/Closing Situation' for entries generated for new fiscal years.")
    type_control_ids = fields.Many2many('account.account.type', 'account_journal_type_rel', 'journal_id', 'type_id', string='Account Types Allowed')
    account_control_ids = fields.Many2many('account.account', 'account_account_type_rel', 'journal_id', 'account_id', string='Accounts Allowed',
        domain=[('deprecated', '=', False)])
    default_credit_account_id = fields.Many2one('account.account', string='Default Credit Account',
        domain=[('deprecated', '=', False)], help="It acts as a default account for credit amount")
    default_debit_account_id = fields.Many2one('account.account', string='Default Debit Account',
        domain=[('deprecated', '=', False)], help="It acts as a default account for debit amount")
    update_posted = fields.Boolean(string='Allow Cancelling Entries',
        help="Check this box if you want to allow the cancellation the entries related to this journal or of the invoice related to this journal")
    group_invoice_lines = fields.Boolean(string='Group Invoice Lines',
        help="If this box is checked, the system will try to group the accounting lines when generating them from invoices.")
    sequence_id = fields.Many2one('ir.sequence', string='Entry Sequence',
        help="This field contains the information related to the numbering of the journal entries of this journal.", required=True, copy=False)
    refund_sequence_id = fields.Many2one('ir.sequence', string='Refund Entry Sequence',
        help="This field contains the information related to the numbering of the refund entries of this journal.", copy=False)
    sequence = fields.Integer(help='Used to order Journals in the dashboard view')

    #groups_id = fields.Many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', string='Groups')
    currency_id = fields.Many2one('res.currency', help='The currency used to enter statement', string="Currency", oldname='currency')
    company_id = fields.Many2one('res.company', string='Company', required=True, index=1, default=lambda self: self.env.user.company_id,
        help="Company related to this journal")

    refund_sequence = fields.Boolean(string='Dedicated Refund Sequence', help="Check this box if you don't want to share the same sequence for invoices and refunds made from this journal", default=False)

    inbound_payment_method_ids = fields.Many2many('account.payment.method', 'account_journal_inbound_payment_method_rel', 'journal_id', 'inbound_payment_method',
        domain=[('payment_type', '=', 'inbound')], string='Debit Methods', default=lambda self: self._default_inbound_payment_methods(),
        help="Means of payment for collecting money. Odoo modules offer various payments handling facilities, "
             "but you can always use the 'Manual' payment method in order to manage payments outside of the software.")
    outbound_payment_method_ids = fields.Many2many('account.payment.method', 'account_journal_outbound_payment_method_rel', 'journal_id', 'outbound_payment_method',
        domain=[('payment_type', '=', 'outbound')], string='Payment Methods', default=lambda self: self._default_outbound_payment_methods(),
        help="Means of payment for sending money. Odoo modules offer various payments handling facilities, "
             "but you can always use the 'Manual' payment method in order to manage payments outside of the software.")
    at_least_one_inbound = fields.Boolean(compute='_methods_compute', store=True)
    at_least_one_outbound = fields.Boolean(compute='_methods_compute', store=True)
    profit_account_id = fields.Many2one('account.account', string='Profit Account', domain=[('deprecated', '=', False)], help="Used to register a profit when the ending balance of a cash register differs from what the system computes")
    loss_account_id = fields.Many2one('account.account', string='Loss Account', domain=[('deprecated', '=', False)], help="Used to register a loss when the ending balance of a cash register differs from what the system computes")

    # Bank journals fields
    bank_account_id = fields.Many2one('res.partner.bank', string="Bank Account", ondelete='restrict', copy=False)
    display_on_footer = fields.Boolean("Show in Invoices Footer", help="Display this bank account on the footer of printed documents like invoices and sales orders.")
    bank_statements_source = fields.Selection([('manual', 'Record Manually')], string='Bank Feeds')
    bank_acc_number = fields.Char(related='bank_account_id.acc_number')
    bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id')

    _sql_constraints = [
        ('code_company_uniq', 'unique (code, name, company_id)', 'The code and name of the journal must be unique per company !'),
    ]

    @api.one
    @api.constrains('currency_id', 'default_credit_account_id', 'default_debit_account_id')
    def _check_currency(self):
        if self.currency_id:
            if self.default_credit_account_id and not self.default_credit_account_id.currency_id.id == self.currency_id.id:
                raise UserError(_('Configuration error!\nThe currency of the journal should be the same than the default credit account.'))
            if self.default_debit_account_id and not self.default_debit_account_id.currency_id.id == self.currency_id.id:
                raise UserError(_('Configuration error!\nThe currency of the journal should be the same than the default debit account.'))

    @api.one
    @api.constrains('type', 'bank_account_id')
    def _check_bank_account(self):
        if self.type == 'bank' and self.bank_account_id:
            if self.bank_account_id.company_id != self.company_id:
                raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % self.company_id.name)
            # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier.
            # Or they are part of a bank journal and their partner_id must be the company's partner_id.
            if self.bank_account_id.partner_id != self.company_id.partner_id:
                raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % self.company_id.name)

    @api.onchange('default_debit_account_id')
    def onchange_debit_account_id(self):
        if not self.default_credit_account_id:
            self.default_credit_account_id = self.default_debit_account_id

    @api.onchange('default_credit_account_id')
    def onchange_credit_account_id(self):
        if not self.default_debit_account_id:
            self.default_debit_account_id = self.default_credit_account_id

    @api.multi
    def unlink(self):
        bank_accounts = self.env['res.partner.bank'].browse()
        for bank_account in self.mapped('bank_account_id'):
            accounts = self.search([('bank_account_id', '=', bank_account.id)])
            if accounts <= self:
                bank_accounts += bank_account
        ret = super(AccountJournal, self).unlink()
        bank_accounts.unlink()
        return ret

    @api.one
    def copy(self, default=None):
        default = dict(default or {})
        default.update(
            code=_("%s (copy)") % (self.code or ''),
            name=_("%s (copy)") % (self.name or ''))
        return super(AccountJournal, self).copy(default)

    @api.multi
    def write(self, vals):
        for journal in self:
            if ('company_id' in vals and journal.company_id.id != vals['company_id']):
                if self.env['account.move'].search([('journal_id', 'in', self.ids)], limit=1):
                    raise UserError(_('This journal already contains items, therefore you cannot modify its company.'))
            if ('code' in vals and journal.code != vals['code']):
                if self.env['account.move'].search([('journal_id', 'in', self.ids)], limit=1):
                    raise UserError(_('This journal already contains items, therefore you cannot modify its short name.'))
                new_prefix = self._get_sequence_prefix(vals['code'], refund=False)
                journal.sequence_id.write({'prefix': new_prefix})
                if journal.refund_sequence_id:
                    new_prefix = self._get_sequence_prefix(vals['code'], refund=True)
                    journal.refund_sequence_id.write({'prefix': new_prefix})
            if 'currency_id' in vals:
                if not 'default_debit_account_id' in vals and self.default_debit_account_id:
                    self.default_debit_account_id.currency_id = vals['currency_id']
                if not 'default_credit_account_id' in vals and self.default_credit_account_id:
                    self.default_credit_account_id.currency_id = vals['currency_id']
            if 'bank_acc_number' in vals and not vals.get('bank_acc_number') and journal.bank_account_id:
                raise UserError(_('You cannot empty the account number once set.\nIf you would like to delete the account number, you can do it from the Bank Accounts list.'))
        result = super(AccountJournal, self).write(vals)

        # Create the bank_account_id if necessary
        if 'bank_acc_number' in vals:
            for journal in self.filtered(lambda r: r.type == 'bank' and not r.bank_account_id):
                journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))

        return result

    @api.model
    def _get_sequence_prefix(self, code, refund=False):
        prefix = code.upper()
        if refund:
            prefix = 'R' + prefix
        return prefix + '/%(range_year)s/'

    @api.model
    def _create_sequence(self, vals, refund=False):
        """ Create new no_gap entry sequence for every new Journal"""
        prefix = self._get_sequence_prefix(vals['code'], refund)
        seq = {
            'name': vals['name'],
            'implementation': 'no_gap',
            'prefix': prefix,
            'padding': 4,
            'number_increment': 1,
            'use_date_range': True,
        }
        if 'company_id' in vals:
            seq['company_id'] = vals['company_id']
        return self.env['ir.sequence'].create(seq)

    @api.model
    def _prepare_liquidity_account(self, name, company, currency_id, type):
        '''
        This function prepares the value to use for the creation of the default debit and credit accounts of a
        liquidity journal (created through the wizard of generating COA from templates for example).

        :param name: name of the bank account
        :param company: company for which the wizard is running
        :param currency_id: ID of the currency in wich is the bank account
        :param type: either 'cash' or 'bank'
        :return: mapping of field names and values
        :rtype: dict
        '''

        # Seek the next available number for the account code
        code_digits = company.accounts_code_digits or 0
        if type == 'bank':
            account_code_prefix = company.bank_account_code_prefix or ''
        else:
            account_code_prefix = company.cash_account_code_prefix or company.bank_account_code_prefix or ''
        for num in xrange(1, 100):
            new_code = str(account_code_prefix.ljust(code_digits - 1, '0')) + str(num)
            rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1)
            if not rec:
                break
        else:
            raise UserError(_('Cannot generate an unused account code.'))

        liquidity_type = self.env.ref('account.data_account_type_liquidity')
        return {
                'name': name,
                'currency_id': currency_id or False,
                'code': new_code,
                'user_type_id': liquidity_type and liquidity_type.id or False,
                'company_id': company.id,
        }

    @api.model
    def create(self, vals):
        company_id = vals.get('company_id', self.env.user.company_id.id)
        if vals.get('type') in ('bank', 'cash'):
            # For convenience, the name can be inferred from account number
            if not vals.get('name') and 'bank_acc_number' in vals:
                vals['name'] = vals['bank_acc_number']

            # If no code provided, loop to find next available journal code
            if not vals.get('code'):
                for num in xrange(1, 100):
                    # journal_code has a maximal size of 5, hence we can enforce the boundary num < 100
                    journal_code = (vals['type'] == 'cash' and 'CSH' or 'BNK') + str(num)
                    journal = self.env['account.journal'].search([('code', '=', journal_code), ('company_id', '=', company_id)], limit=1)
                    if not journal:
                        vals['code'] = journal_code
                        break
                else:
                    raise UserError(_("Cannot generate an unused journal code. Please fill the 'Shortcode' field."))

            # Create a default debit/credit account if not given
            default_account = vals.get('default_debit_account_id') or vals.get('default_credit_account_id')
            if not default_account:
                company = self.env['res.company'].browse(company_id)
                account_vals = self._prepare_liquidity_account(vals.get('name'), company, vals.get('currency_id'), vals.get('type'))
                default_account = self.env['account.account'].create(account_vals)
                vals['default_debit_account_id'] = default_account.id
                vals['default_credit_account_id'] = default_account.id

        # We just need to create the relevant sequences according to the chosen options
        if not vals.get('sequence_id'):
            vals.update({'sequence_id': self.sudo()._create_sequence(vals).id})
        if vals.get('type') in ('sale', 'purchase') and vals.get('refund_sequence') and not vals.get('refund_sequence_id'):
            vals.update({'refund_sequence_id': self.sudo()._create_sequence(vals, refund=True).id})

        journal = super(AccountJournal, self).create(vals)

        # Create the bank_account_id if necessary
        if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'):
            journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))

        return journal

    def set_bank_account(self, acc_number, bank_id=None):
        """ Create a res.partner.bank and set it as value of the  field bank_account_id """
        self.ensure_one()
        self.bank_account_id = self.env['res.partner.bank'].create({
            'acc_number': acc_number,
            'bank_id': bank_id,
            'company_id': self.company_id.id,
            'currency_id': self.currency_id.id,
            'partner_id': self.company_id.partner_id.id,
        }).id

    @api.multi
    @api.depends('name', 'currency_id', 'company_id', 'company_id.currency_id')
    def name_get(self):
        res = []
        for journal in self:
            currency = journal.currency_id or journal.company_id.currency_id
            name = "%s (%s)" % (journal.name, currency.name)
            res += [(journal.id, name)]
        return res

    @api.multi
    @api.depends('inbound_payment_method_ids', 'outbound_payment_method_ids')
    def _methods_compute(self):
        for journal in self:
            journal.at_least_one_inbound = bool(len(journal.inbound_payment_method_ids))
            journal.at_least_one_outbound = bool(len(journal.outbound_payment_method_ids))
Beispiel #13
0
class MrpProduction(models.Model):
    _inherit = 'mrp.production'
    _order = 'name desc'

    date_planned = fields.Datetime(readonly=False)  # Redefined
    routing_id = fields.Many2one(ondelete='restrict')  # Redefined
    date = fields.Datetime('Creation Date',
                           states={
                               'cancel': [('readonly', True)],
                               'done': [('readonly', True)]
                           },
                           default=fields.Datetime.now,
                           copy=False)
    state = fields.Selection(PRODUCTION_STATES)  # Redefined
    note = fields.Text('Notes')
    workcenter_lines = fields.One2many(readonly=False)  # Redefined
    origin = fields.Char(
        readonly=False,  # Redefined
        states={
            'cancel': [('readonly', True)],
            'done': [('readonly', True)]
        })
    color_production = fields.Integer('Color production',
                                      compute='_get_color_production',
                                      readonly=True)
    theo_cost = fields.Float('Theorical Cost',
                             digits=dp.get_precision('Product Price'),
                             copy=False)
    production_type = fields.Selection(PRODUCTION_TYPES,
                                       'Type of production',
                                       default='normal',
                                       copy=False)

    @api.multi
    def _get_color_production(self):
        for prod in self:
            color_production = -1  # blanco (cero da error al cargar la vista kanban)
            if prod.priority == '0':  # Prioridad no urgente
                color_production = 4  # verde claro
            elif prod.priority == '1':  # Prioridad normal
                color_production = 3  # amarillo
            elif prod.priority == '2':  # Prioridad urgente
                color_production = 2  # rojo claro
            elif prod.priority == '3':  # Prioridad muy urgente
                color_production = 1  # gris
            prod.color_production = color_production

    @api.multi
    def modify_consumption(self):
        ctx = dict(self._context,
                   active_model=self._name,
                   active_ids=self.ids,
                   active_id=self.ids[0])
        mod_cons_obj = self.env['mrp.modify.consumption'].with_context(ctx)
        return mod_cons_obj.create({}).wizard_view()

    @api.model
    def _costs_generate(self, production):
        """ Calculates total costs at the end of the production.
        @param production: Id of production order.
        @return: Calculated amount.
        """
        amount = 0.0
        analytic_line_obj = self.env['account.analytic.line']
        for wc_line in production.workcenter_lines:
            wc = wc_line.workcenter_id
            if wc.costs_journal_id and wc.costs_general_account_id:
                # Cost per hour
                value = wc_line.hour * wc.costs_hour
                account = wc.costs_hour_account_id.id
                if value and account:
                    amount += value
                    analytic_line_obj.sudo().create({
                        'name':
                        wc_line.name + ' (H)',
                        'amount':
                        value,
                        'account_id':
                        account,
                        'general_account_id':
                        wc.costs_general_account_id.id,
                        'journal_id':
                        wc.costs_journal_id.id,
                        'ref':
                        wc.code,
                        'product_id':
                        wc.product_id.id,
                        'unit_amount':
                        wc_line.hour,
                        'product_uom_id':
                        wc.product_id and wc.product_id.uom_id.id or False
                    })
        return amount

    @api.model
    def _make_production_produce_line(self, production):
        move_id = super(MrpProduction,
                        self)._make_production_produce_line(production)
        move = self.env['stock.move'].browse(move_id)
        move_name = _('PROD: %s') % production.name
        move.write({'name': move_name})
        return move_id

    @api.onchange('product_uos_qty')
    def product_uos_qty_change(self):
        if self.product_id.uos_id:
            qty_uom = float(self.product_uos_qty /
                            (self.product_id.uos_coeff or 1.0))
            self.product_qty = qty_uom
            self.product_uos = self.product_id.uos_id
        else:
            self.product_uos_qty = False
            self.product_uos = False

    @api.model
    def action_produce(self,
                       production_id,
                       production_qty,
                       production_mode,
                       wiz=False):
        stock_move_obj = self.env['stock.move']
        uom_obj = self.env['product.uom']
        production = self.browse(production_id)
        production_qty_uom = uom_obj._compute_qty(
            production.product_uom.id, production_qty,
            production.product_id.uom_id.id)
        precision = self.env['decimal.precision'].precision_get(
            'Product Unit of Measure')
        main_production_move = False
        default_mode = self._context.get('default_mode', False)
        if production_mode == 'produce':  # New Case: Produce Only
            produced_products = {}
            for produced_product in production.move_created_ids2:
                if produced_product.scrapped:
                    continue
                if not produced_products.get(produced_product.product_id.id,
                                             False):
                    produced_products[produced_product.product_id.id] = 0
                produced_products[produced_product.product_id.
                                  id] += produced_product.product_qty
            for produce_product in production.move_created_ids:
                subproduct_factor = self._get_subproduct_factor(
                    production.id, produce_product.id)
                lot_id = wiz and wiz.lot_id.id or False
                qty = min(subproduct_factor * production_qty_uom,
                          produce_product.product_qty
                          )  # Needed when producing more than maximum quantity
                new_moves = produce_product.action_consume(
                    qty,
                    location_id=produce_product.location_id.id,
                    restrict_lot_id=lot_id)
                stock_move_obj.browse(new_moves).write(
                    {'production_id': production_id})
                remaining_qty = subproduct_factor * production_qty_uom - qty
                if not float_is_zero(remaining_qty,
                                     precision_digits=precision):
                    # In case you need to make more than planned
                    # consumed more in wizard than previously planned
                    extra_move_id = produce_product.copy(
                        default={
                            'product_uom_qty': remaining_qty,
                            'production_id': production_id
                        })
                    extra_move_id.action_confirm()
                    extra_move_id.action_done()
                if produce_product.product_id == production.product_id:
                    main_production_move = produce_product.id
            if default_mode != 'consume' and not production.move_created_ids:
                production.signal_workflow('button_finished_validated')
        else:
            if not main_production_move:
                main_production_move = production.move_created_ids2 and production.move_created_ids2[
                    0].id
            # Añadimos al contexto 'main_production_move'
            # para poder escribirlo en el write y en el action_consume()
            self = self.with_context(main_production_move=main_production_move)
            res = super(MrpProduction, self).action_produce(production_id,
                                                            production_qty,
                                                            production_mode,
                                                            wiz=wiz)
            if default_mode != 'consume' and not production.move_created_ids:
                production.signal_workflow('button_finished_validated')
            if default_mode == 'consume':
                # Custom behaivor, set closed state
                production.signal_workflow('button_validated_closed')
        return True

    @api.multi
    def action_finished(self):
        for production in self:
            production.write({'state': 'finished'})
        return True

    @api.multi
    def action_validated(self):
        tmpl_obj = self.env['product.template']
        for production in self:
            theo_cost = tmpl_obj._calc_price(production.bom_id, test=True)
            production.write({'state': 'validated', 'theo_cost': theo_cost})
        return True

    @api.multi
    def action_close(self):
        tmpl_obj = self.env['product.template']
        precision = self.env['decimal.precision'].precision_get(
            'Product Price')
        for production in self:
            date = max([
                x.date for x in production.move_created_ids2
                if x.state == 'done' and not x.scrapped
            ] or [None])
            for move in production.move_lines2.filtered(
                    lambda r: r.state == 'done'):
                # Establecemos en los movimiento de consumos los precios de coste de producto que tenía en la fecha
                # que se realizó el producto finalizado, para que coincida con la misma posición
                # en la que se calcula el theo_cost. Esto es debido a que los consumos se pueden hacer más
                # tarde que la validación del producto terminado (action_validated)
                price_unit = tmpl_obj.get_history_price(
                    move.product_id.product_tmpl_id.id,
                    move.company_id.id,
                    date=date)
                # Aplicamos el redondeo que tendría el campo standard_price,
                # ya que get_history_price devuelve el valor sin precision
                price_unit = float_round(price_unit,
                                         precision_digits=precision)
                price_unit = price_unit or move.product_id.standard_price
                move.write({'price_unit': price_unit})
            production.write({'state': 'closed'})
        return True

    @api.multi
    def action_cancel(self):
        """ Cancels the production order and related stock moves.
        @return: True
        """
        res = super(MrpProduction, self).action_cancel()
        # Put related procurements in cancel state
        proc_obj = self.env['procurement.order']
        procs = proc_obj.search([('production_id', 'in', self.ids)])
        procs.write({'state': 'cancel'})
        return res

    @api.multi
    def action_in_production(self):
        """
        Overwrite to set startworking state of all workcenter lines instead
        only one.
        """
        for workcenter_line in self.mapped('workcenter_lines'):
            workcenter_line.signal_workflow('button_start_working')
        return super(MrpProduction, self).action_in_production()

    @api.multi
    def action_production_end(self):
        prod_line_obj = self.env['mrp.production.product.line']
        res = super(MrpProduction, self).action_production_end()
        for production in self:
            bom = production.bom_id
            finished_qty = sum([
                x.product_uom_qty for x in production.move_created_ids2
                if x.state == 'done' and not x.scrapped
            ])
            factor = self.env['product.uom']._compute_qty(
                production.product_uom.id, finished_qty, bom.product_uom.id)
            new_qty = factor / bom.product_qty
            routing_id = production.routing_id.id
            result, result2 = self.env['mrp.bom']._bom_explode(
                bom, production.product_id, new_qty, routing_id=routing_id)
            prod_lines = result
            production.product_lines.unlink()
            for line in prod_lines:
                line['production_id'] = production.id
                prod_line_obj.create(line)
        # Nos aseguramos de que la trazabilidad hacia arriba de la producción es correcta
        # Hay casos en los que se eliminan las lineas de consumos y se agragan nuevas,
        # momento en el que se pierde la traza
        self.update_production_traceability()
        return res

    @api.multi
    def update_production_traceability(self):
        for production in self:
            for move in production.move_created_ids2.filtered(
                    lambda r: r.state == 'done'):
                if move.production_id:  # Is final production move
                    raw_ids = move.production_id.move_lines
                    raw_ids |= move.production_id.move_lines2.filtered(
                        lambda r: r.state != 'cancel' and not r.scrapped)
                    move.write({'parent_ids': [(6, 0, raw_ids.ids)]})
        return True

    @api.multi
    def unlink(self):
        """ Unlink the production order and related stock moves.
        @return: True
        """
        if any(x.state not in ('draft', 'confirmed', 'ready', 'in_production',
                               'cancel') for x in self):
            raise exceptions.Warning(
                _('Error!'),
                _('You cannot delete a production which is not cancelled.'))
        prods_to_cancel = self.filtered(lambda r: r.state != 'cancel')
        if prods_to_cancel:
            prods_to_cancel.action_cancel()
        moves_to_unlink = self.mapped('move_created_ids2') + self.mapped(
            'move_lines2')
        moves_to_unlink.unlink()
        wc_lines_to_unlink = self.mapped('workcenter_lines')
        wc_lines_to_unlink.unlink()
        res = super(MrpProduction, self).unlink()
        return res

    @api.multi
    def update_production_priority(self):
        domain = [('priority', '!=', '3'),
                  ('state', 'in', ['confirmed', 'ready'])]
        production_ids = self or self.search(domain)
        for production in production_ids:
            product_id = production.product_id
            ctx = dict(self._context, location=production.location_dest_id.id)
            product_available = product_id.with_context(
                ctx)._product_available()[product_id.id]
            qty_to_compare = product_available[
                'qty_available'] - product_available['outgoing_qty']
            company_id = production.company_id
            domain = company_id and [('company_id', '=', company_id.id)] or []
            domain.append(('product_id', '=', product_id.id))
            op = self.env['stock.warehouse.orderpoint'].search(domain, limit=1)
            min_qty = security_qty = 0
            if op:
                min_qty = min(op.product_min_qty, op.product_max_qty)
                security_qty = op.product_security_qty
            if qty_to_compare <= 0:
                priority = '2'  # Urgente
            elif qty_to_compare <= security_qty:
                priority = '1'  # Normal
            elif qty_to_compare <= min_qty:
                priority = '0'  # No urgente
            else:
                priority = '0'  # No urgente
            if production.priority != priority:
                production.write({'priority': priority})
        return True
Beispiel #14
0
class MrpProductionWorkcenterLine(models.Model):
    _inherit = 'mrp.production.workcenter.line'
    _order = 'id'

    @api.multi
    def _read_group_workcenter_ids(self,
                                   domain,
                                   read_group_order=None,
                                   access_rights_uid=None):
        workcenter_obj = self.env['mrp.workcenter']
        workcenter_line_obj = self.env['mrp.production.workcenter.line']
        access_rights_uid = access_rights_uid or self._uid
        order = workcenter_obj._order
        if read_group_order == 'workcenter_id desc':
            order = '%s desc' % order
        workcenter_ids = workcenter_obj._search(
            [], order=order, access_rights_uid=access_rights_uid)
        workcenter_ids = workcenter_obj.sudo(access_rights_uid).browse(
            workcenter_ids)
        result = workcenter_ids.name_get()
        # restore order of the search
        result.sort(lambda x, y: cmp(workcenter_ids.ids.index(x[0]),
                                     workcenter_ids.ids.index(y[0])))
        fold = {}
        for workcenter in workcenter_ids:
            domain = [('workcenter_id', '=', workcenter.id),
                      ('production_state', 'in', ('ready', 'confirmed',
                                                  'in_production'))]
            count = workcenter_line_obj._search(
                domain, count=True, access_rights_uid=access_rights_uid)
            fold[workcenter.id] = False if count else True
        return result, fold

    _group_by_full = {'workcenter_id': _read_group_workcenter_ids}

    operators_ids = fields.Many2many('hr.employee',
                                     string='Operators',
                                     rel='hr_employee_mrp_prod_workc_line_rel',
                                     id1='workcenter_line_id',
                                     id2='employee_id')
    production_stops_ids = fields.One2many('production.stops',
                                           'production_workcenter_line_id',
                                           'Production stops')
    time_start = fields.Float('Time before prod.',
                              help="Time in hours for the setup.")
    time_stop = fields.Float('Time after prod.',
                             help="Time in hours for the cleaning.")
    gasoleo_start = fields.Float('Gasoleo start')
    gasoleo_stop = fields.Float('Gasoleo stop')
    color = fields.Integer('Color Index')
    move_id = fields.Many2one('stock.move',
                              'Move',
                              related='production_id.move_prod_id',
                              readonly=True)
    color_production = fields.Integer('Color production',
                                      related='production_id.color_production',
                                      readonly=True)
    routing_id = fields.Many2one('mrp.routing',
                                 'Routing',
                                 related='production_id.routing_id',
                                 readonly=True)
    real_time = fields.Float('Real time')
    priority = fields.Selection([('0', 'Not urgent'), ('1', 'Normal'),
                                 ('2', 'Urgent'), ('3', 'Very Urgent')],
                                'Priority',
                                related='production_id.priority',
                                readonly=True,
                                store=True)
    production_type = fields.Selection(PRODUCTION_TYPES,
                                       'Type of production',
                                       related='production_id.production_type',
                                       readonly=True)
    product_uos_qty = fields.Float('Product UoS Quantity',
                                   related='production_id.product_uos_qty',
                                   readonly=True)
    product_uos = fields.Many2one('product.uom',
                                  'Product UoS',
                                  related='production_id.product_uos',
                                  readonly=True)
    kanban_name = fields.Char('Kanban name',
                              compute='_get_kanban_name',
                              readonly=True)
    availability_ratio = fields.Float(
        'Availability ratio',
        size=8,
        default=1,
        help="Availability ratio expected for this workcenter line. "
        "The estimated time was calculated according to this ratio.")
    workorder_planned_state = fields.Selection([('0', 'No planned'),
                                                ('1', 'Planned')],
                                               'Planned state')
    production_state = fields.Selection(PRODUCTION_STATES,
                                        'Production Status',
                                        related='production_id.state',
                                        readonly=True)

    @api.multi
    def _get_kanban_name(self):
        for line in self:
            line.kanban_name = line.production_id.name + u' - ' + (
                (line.name).split('-')[0])[:-1]

    @api.multi
    def modify_production_order_state(self, action):
        """ Modifies production order state if work order state is changed.
        @param action: Action to perform.
        @return: Nothing
        """
        self.ensure_one()
        prod = self.production_id
        if action == 'start':
            if prod.state == 'confirmed':
                prod.force_production()
                prod.signal_workflow('button_produce')
            elif prod.state in ('ready', 'in_production', 'finished',
                                'validated', 'closed'):
                prod.signal_workflow('button_produce')
            else:
                raise exceptions.Warning(
                    _('Error!'),
                    _('Manufacturing order cannot be started in state "%s"!') %
                    (prod.state))
        else:
            return super(MrpProductionWorkcenterLine,
                         self).modify_production_order_state(action)
        return

    @api.multi
    def open_mrp_production_form(self):
        self.ensure_one()
        prod = self.production_id
        if not prod:
            return False
        return {
            'name': 'MRP Production',
            'view_mode': 'form',
            'view_type': 'form',
            'res_model': 'mrp.production',
            'res_id': prod.id,
            'type': 'ir.actions.act_window',
            'nodestroy': True,
            'target': 'current',
            'context': self._context
        }

    @api.multi
    def unlink(self):
        if any(x.state not in ('draft', 'cancel') for x in self):
            raise exceptions.Warning(
                _('Error!'),
                _('You cannot delete a work order which is not in draft or cancelled.'
                  ))
        res = super(MrpProductionWorkcenterLine, self).unlink()
        return res
class task_subject(models.Model):
    _name = 'task.subject'

    name = fields.Char('Subject')
    description = fields.Char('Content')
    alert_days = fields.Integer('Alert Before Days')
class account_vat_ledger(models.Model):
    _inherit = "account.vat.ledger"

    REGINFO_CV_ALICUOTAS = fields.Text(
        'REGINFO_CV_ALICUOTAS',
        readonly=True,
    )
    REGINFO_CV_COMPRAS_IMPORTACIONES = fields.Text(
        'REGINFO_CV_COMPRAS_IMPORTACIONES',
        readonly=True,
    )
    REGINFO_CV_CBTE = fields.Text(
        'REGINFO_CV_CBTE',
        readonly=True,
    )
    REGINFO_CV_CABECERA = fields.Text(
        'REGINFO_CV_CABECERA',
        readonly=True,
    )
    vouchers_file = fields.Binary(
        _('Vouchers File'),
        compute='get_files',
        readonly=True
    )
    vouchers_filename = fields.Char(
        _('Vouchers Filename'),
        readonly=True,
        compute='get_files',
    )
    aliquots_file = fields.Binary(
        _('Aliquots File'),
        compute='get_files',
        readonly=True
    )
    aliquots_filename = fields.Char(
        _('Aliquots Filename'),
        readonly=True,
        compute='get_files',
    )
    import_aliquots_file = fields.Binary(
        _('Import Aliquots File'),
        compute='get_files',
        readonly=True
    )
    import_aliquots_filename = fields.Char(
        _('Import Aliquots Filename'),
        readonly=True,
        compute='get_files',
    )
    prorate_tax_credit = fields.Boolean(
        'Prorate Tax Credit',
    )
    prorate_type = fields.Selection(
        [('global', 'Global'), ('by_voucher', 'By Voucher')],
        'Prorate Type',
    )
    tax_credit_computable_amount = fields.Float(
        'Credit Computable Amount',
    )
    sequence = fields.Integer(
        'Sequence',
        default=0,
        required=True,
        help='Se deberá indicar si la presentación es Original (00) o '
        'Rectificativa y su orden'
    )

    @api.model
    def format_amount(self, amount, padding=15, decimals=2, invoice=False):
        # get amounts on correct sign despite conifiguration on taxes and tax
        # codes
        # TODO
        # remove this and perhups invoice argument (we always send invoice)
        # for invoice refund we dont change sign (we do this before)
        # if invoice:
        #     amount = abs(amount)
        #     if invoice.type in ['in_refund', 'out_refund']:
        #         amount = -1.0 * amount
        # if amount < 0:
        #     template = "-{:0>%dd}" % (padding-1)
        # else:
        template = "{:0>%dd}" % (padding)
        return template.format(
            int(round(abs(amount) * 10**decimals, decimals)))

    @api.one
    @api.depends(
        'REGINFO_CV_CBTE',
        'REGINFO_CV_ALICUOTAS',
        'type',
        # 'period_id.name'
    )
    def get_files(self):
        # segun vimos aca la afip espera "ISO-8859-1" en vez de utf-8
        # http://www.planillasutiles.com.ar/2015/08/
        # como-descargar-los-archivos-de.html
        if self.REGINFO_CV_ALICUOTAS:
            self.aliquots_filename = _('Alicuots_%s_%s.txt') % (
                self.type,
                self.date_to,
                # self.period_id.name
            )
            self.aliquots_file = base64.encodestring(
                self.REGINFO_CV_ALICUOTAS.encode('ISO-8859-1'))
        if self.REGINFO_CV_COMPRAS_IMPORTACIONES:
            self.import_aliquots_filename = _('Import_Alicuots_%s_%s.txt') % (
                self.type,
                self.date_to,
                # self.period_id.name
            )
            self.import_aliquots_file = base64.encodestring(
                self.REGINFO_CV_COMPRAS_IMPORTACIONES.encode('ISO-8859-1'))
        if self.REGINFO_CV_CBTE:
            self.vouchers_filename = _('Vouchers_%s_%s.txt') % (
                self.type,
                self.date_to,
                # self.period_id.name
            )
            self.vouchers_file = base64.encodestring(
                self.REGINFO_CV_CBTE.encode('ISO-8859-1'))

    @api.one
    def compute_citi_data(self):
        # no lo estamos usando
        # self.get_REGINFO_CV_CABECERA()
        self.get_REGINFO_CV_CBTE()
        self.get_REGINFO_CV_ALICUOTAS()
        if self.type == 'purchase':
            self.get_REGINFO_CV_COMPRAS_IMPORTACIONES()

    @api.model
    def get_partner_document_code(self, partner):
        # TODO agregar validaciones para los que se presentan sin numero de
        # documento para operaciones menores a 1000 segun doc especificacion
        # regimen de...
        if partner.main_id_category_id.afip_code:
            return "{:0>2d}".format(partner.main_id_category_id.afip_code)
        else:
            return '99'

    @api.model
    def get_partner_document_number(self, partner):
        # TODO agregar validaciones para los que se presentan sin numero de
        # documento para operaciones menores a 1000 segun doc especificacion
        # regimen de...
        return (partner.main_id_number or '').rjust(20, '0')

    @api.model
    def get_point_of_sale(self, invoice):
        # this invalidate cache is to fix that when we request pos number
        # all invoices of the vat ledger, no matter citi export or not,
        # are requested to compute pos number
        invoice.invalidate_cache()
        return "{:0>5d}".format(invoice.point_of_sale_number)

    @api.multi
    def get_citi_invoices(self):
        self.ensure_one()
        return self.env['account.invoice'].search([
            ('document_type_id.export_to_citi', '=', True),
            ('id', 'in', self.invoice_ids.ids)], order='date_invoice asc')

    @api.one
    def get_REGINFO_CV_CBTE(self):
        res = []
        invoices = self.get_citi_invoices()
        invoices.check_argentinian_invoice_taxes()
        if self.type == 'purchase':
            partners = invoices.mapped('commercial_partner_id').filtered(
                lambda r: r.main_id_category_id.afip_code in (
                    False, 99) or not r.main_id_number)
            if partners:
                raise ValidationError(_(
                    "On purchase citi, partner document is mandatory and "
                    "partner document type must be different from 99. "
                    "Partners %s") % partners.ids)

        for inv in invoices:
            # only vat taxes with codes 3, 4, 5, 6, 8, 9
            # segun: http://contadoresenred.com/regimen-de-informacion-de-
            # compras-y-ventas-rg-3685-como-cargar-la-informacion/
            # empezamos a contar los codigos 1 (no gravado) y 2 (exento)
            # si no hay alicuotas, sumamos una de esta con 0, 0, 0 en detalle
            # usamos mapped por si hay afip codes duplicados (ej. manual y
            # auto)
            cant_alicuotas = len(inv.vat_tax_ids.filtered(
                lambda r: r.tax_id.tax_group_id.afip_code in [3, 4, 5, 6, 8, 9]
            ).mapped('tax_id.tax_group_id.afip_code'))
            # iva no corresponde no suma
            if not cant_alicuotas and inv.vat_tax_ids.filtered(
                    lambda r: r.tax_id.tax_group_id.afip_code in [1, 2]):
                cant_alicuotas = 1

            row = [
                # Campo 1: Fecha de comprobante
                fields.Date.from_string(inv.date_invoice).strftime('%Y%m%d'),

                # Campo 2: Tipo de Comprobante.
                "{:0>3d}".format(int(inv.document_type_id.code)),

                # Campo 3: Punto de Venta
                self.get_point_of_sale(inv),

                # Campo 4: Número de Comprobante
                # TODO agregar estos casos de uso
                # Si se trata de un comprobante de varias hojas, se deberá
                # informar el número de documento de la primera hoja, teniendo
                # en cuenta lo normado en el  artículo 23, inciso a), punto
                # 6., de la Resolución General N° 1.415, sus modificatorias y
                # complementarias.
                # En el supuesto de registrar de manera agrupada por totales
                # diarios, se deberá consignar el primer número de comprobante
                # del rango a considerar.
                "{:0>20d}".format(inv.invoice_number)
            ]

            if self.type == 'sale':
                # Campo 5: Número de Comprobante Hasta.
                # TODO agregar esto En el resto de los casos se consignará el
                # dato registrado en el campo 4
                row.append("{:0>20d}".format(inv.invoice_number))
            else:
                # Campo 5: Despacho de importación
                if inv.document_type_id.code == '66':
                    row.append(
                        (inv.document_number or inv.number or '').rjust(
                            16, '0'))
                else:
                    row.append(''.rjust(16, ' '))

            row += [
                # Campo 6: Código de documento del comprador.
                self.get_partner_document_code(inv.commercial_partner_id),

                # Campo 7: Número de Identificación del comprador
                self.get_partner_document_number(inv.commercial_partner_id),

                # Campo 8: Apellido y Nombre del comprador.
                inv.commercial_partner_id.name.ljust(30, ' ')[:30],
                # inv.commercial_partner_id.name.encode(
                #     'ascii', 'replace').ljust(30, ' ')[:30],

                # Campo 9: Importe Total de la Operación.
                self.format_amount(inv.amount_total, invoice=inv),

                # Campo 10: Importe total de conceptos que no integran el
                # precio neto gravado
                self.format_amount(inv.vat_untaxed_base_amount, invoice=inv),
            ]

            if self.type == 'sale':
                row += [
                    # Campo 11: Percepción a no categorizados
                    self.format_amount(
                        sum(inv.tax_line_ids.filtered(lambda r: (
                            r.tax_id.tax_group_id.type == 'perception' and
                            r.tax_id.tax_group_id.tax == 'vat' and
                            r.tax_id.tax_group_id.application \
                            == 'national_taxes')
                        ).mapped('amount')), invoice=inv),

                    # Campo 12: Importe de operaciones exentas
                    self.format_amount(
                        inv.vat_exempt_base_amount, invoice=inv),
                ]
            else:
                row += [
                    # Campo 11: Importe de operaciones exentas
                    self.format_amount(
                        inv.vat_exempt_base_amount, invoice=inv),

                    # Campo 12: Importe de percepciones o pagos a cuenta del
                    # Impuesto al Valor Agregado
                    self.format_amount(
                        sum(inv.tax_line_ids.filtered(lambda r: (
                            r.tax_id.tax_group_id.type == 'perception' and
                            r.tax_id.tax_group_id.tax == 'vat' and
                            r.tax_id.tax_group_id.application \
                            == 'national_taxes')
                        ).mapped(
                            'amount')), invoice=inv),
                ]

            row += [
                # Campo 13: Importe de percepciones o pagos a cuenta de
                # impuestos nacionales
                self.format_amount(
                    sum(inv.tax_line_ids.filtered(lambda r: (
                        r.tax_id.tax_group_id.type == 'perception' and
                        r.tax_id.tax_group_id.tax != 'vat' and
                        r.tax_id.tax_group_id.application == 'national_taxes')
                    ).mapped('amount')), invoice=inv),

                # Campo 14: Importe de percepciones de ingresos brutos
                self.format_amount(
                    sum(inv.tax_line_ids.filtered(lambda r: (
                        r.tax_id.tax_group_id.type == 'perception' and
                        r.tax_id.tax_group_id.application \
                        == 'provincial_taxes')
                    ).mapped('amount')), invoice=inv),

                # Campo 15: Importe de percepciones de impuestos municipales
                self.format_amount(
                    sum(inv.tax_line_ids.filtered(lambda r: (
                        r.tax_id.tax_group_id.type == 'perception' and
                        r.tax_id.tax_group_id.application == 'municipal_taxes')
                    ).mapped('amount')), invoice=inv),

                # Campo 16: Importe de impuestos internos
                self.format_amount(
                    sum(inv.tax_line_ids.filtered(
                        lambda r: r.tax_id.tax_group_id.application \
                        == 'internal_taxes'
                    ).mapped('amount')), invoice=inv),

                # Campo 17: Código de Moneda
                str(inv.currency_id.afip_code),

                # Campo 18: Tipo de Cambio
                self.format_amount(
                    inv.currency_rate or inv.currency_id.with_context(
                        date=inv.date_invoice).compute(
                            1., inv.company_id.currency_id),
                    padding=10, decimals=6),

                # Campo 19: Cantidad de alícuotas de IVA
                str(cant_alicuotas),

                # Campo 20: Código de operación.
                # WARNING. segun la plantilla es 0 si no es ninguna
                # TODO ver que no se informe un codigo si no correpsonde,
                # tal vez da error
                inv.fiscal_position_id.afip_code or ' ',
            ]

            if self.type == 'sale':
                row += [
                    # Campo 21: Otros Tributos
                    self.format_amount(
                        sum(inv.tax_line_ids.filtered(
                            lambda r: r.tax_id.tax_group_id.application \
                            == 'others'
                        ).mapped('amount')), invoice=inv),

                    # Campo 22: vencimiento comprobante (no figura en
                    # instructivo pero si en aplicativo) para tique y factura
                    # de exportacion no se informa
                    (inv.document_type_id.code in ['81', '82', '83', '19'] and
                        '00000000' or
                        fields.Date.from_string(
                            inv.date_due or inv.date_invoice).strftime(
                            '%Y%m%d')),
                ]
            else:
                # Campo 21: Crédito Fiscal Computable
                if self.prorate_tax_credit:
                    if self.prorate_type == 'global':
                        row.append(self.format_amount(0), invoice=inv)
                    else:
                        # row.append(self.format_amount(0))
                        raise ValidationError(_(
                            'by_voucher not implemented yet'))
                else:
                    row.append(self.format_amount(inv.vat_amount, invoice=inv))

                row += [
                    # Campo 22: Otros Tributos
                    self.format_amount(
                        sum(inv.tax_line_ids.filtered(lambda r: (
                            r.tax_id.tax_group_id.application \
                            == 'others')).mapped(
                            'amount')), invoice=inv),

                    # TODO implementar estos 3
                    # Campo 23: CUIT Emisor / Corredor
                    # Se informará sólo si en el campo "Tipo de Comprobante" se
                    # consigna '033', '058', '059', '060' ó '063'. Si para
                    # éstos comprobantes no interviene un tercero en la
                    # operación, se consignará la C.U.I.T. del informante. Para
                    # el resto de los comprobantes se completará con ceros
                    self.format_amount(0, padding=11, invoice=inv),

                    # Campo 24: Denominación Emisor / Corredor
                    ''.ljust(30, ' ')[:30],

                    # Campo 25: IVA Comisión
                    # Si el campo 23 es distinto de cero se consignará el
                    # importe del I.V.A. de la comisión
                    self.format_amount(0, invoice=inv),
                ]
            res.append(''.join(row))
        self.REGINFO_CV_CBTE = '\r\n'.join(res)

    @api.multi
    def get_tax_row(self, invoice, base, code, tax_amount):
        self.ensure_one()
        inv = invoice
        row = [
            # Campo 1: Tipo de Comprobante
            "{:0>3d}".format(int(inv.document_type_id.code)),

            # Campo 2: Punto de Venta
            self.get_point_of_sale(inv),

            # Campo 3: Número de Comprobante
            "{:0>20d}".format(inv.invoice_number),
        ]
        if self.type == 'sale':
            row += [
                # Campo 4: Importe Neto Gravado
                self.format_amount(base, invoice=inv),

                # Campo 5: Alícuota de IVA.
                str(code).rjust(4, '0'),

                # Campo 6: Impuesto Liquidado.
                self.format_amount(tax_amount, invoice=inv),
            ]
        else:
            row += [
                # Campo 4: Código de documento del vendedor
                self.get_partner_document_code(
                    inv.commercial_partner_id),

                # Campo 5: Número de identificación del vendedor
                self.get_partner_document_number(
                    inv.commercial_partner_id),

                # Campo 6: Importe Neto Gravado
                self.format_amount(base, invoice=inv),

                # Campo 7: Alícuota de IVA.
                str(code).rjust(4, '0'),

                # Campo 8: Impuesto Liquidado.
                self.format_amount(tax_amount, invoice=inv),
            ]
        return row

    @api.one
    def get_REGINFO_CV_ALICUOTAS(self):
        res = []
        for inv in self.get_citi_invoices().filtered(
                lambda r: r.document_type_id.code != '66'):
            vat_taxes = inv.vat_tax_ids.filtered(
                lambda r: r.tax_id.tax_group_id.afip_code in [
                    3, 4, 5, 6, 8, 9])

            # if only exempt or no gravado, we add one line with 0, 0, 0
            # no corresponde no lo llevamos
            if not vat_taxes and inv.vat_tax_ids.filtered(
                    lambda r: r.tax_id.tax_group_id.afip_code in [1, 2]):
                res.append(''.join(self.get_tax_row(inv, 0.0, 3, 0.0)))

            # we group by afip_code
            for afip_code in vat_taxes.mapped('tax_id.tax_group_id.afip_code'):
                taxes = vat_taxes.filtered(
                    lambda x: x.tax_id.tax_group_id.afip_code == afip_code)
                res.append(''.join(self.get_tax_row(
                    inv,
                    sum(taxes.mapped('base')),
                    afip_code,
                    sum(taxes.mapped('amount')),
                )))
        self.REGINFO_CV_ALICUOTAS = '\r\n'.join(res)

    @api.one
    def get_REGINFO_CV_COMPRAS_IMPORTACIONES(self):
        res = []
        for inv in self.get_citi_invoices().filtered(
                lambda r: r.document_type_id.code == '66'):
            vat_taxes = inv.vat_tax_ids.filtered(
                lambda r: r.tax_id.tax_group_id.afip_code in [
                    3, 4, 5, 6, 8, 9])

            # we group by afip_code
            for afip_code in vat_taxes.mapped('tax_id.tax_group_id.afip_code'):
                taxes = vat_taxes.filtered(
                    lambda x: x.tax_id.tax_group_id.afip_code == afip_code)
                base = sum(taxes.mapped('base'))
                # base_amount = sum(taxes.mapped('base_amount'))
                amount = sum(taxes.mapped('amount'))
                row = [
                    # Campo 1: Despacho de importación.
                    (inv.document_number or inv.number or '').rjust(
                        16, '0'),

                    # Campo 2: Importe Neto Gravado
                    self.format_amount(base, invoice=inv),

                    # Campo 3: Alícuota de IVA
                    str(afip_code).rjust(4, '0'),

                    # Campo 4: Impuesto Liquidado.
                    self.format_amount(amount, invoice=inv),
                ]
                res.append(''.join(row))
        self.REGINFO_CV_COMPRAS_IMPORTACIONES = '\r\n'.join(res)
Beispiel #17
0
class sessionpos(models.Model):

    def _fun_difference(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            totali = 0
            totali = session.cash_register_balance_end
            totalf = session.cash_register_balance_end_real
            for order in session.order_ids:
                flag = False
                for producto in order.lines:
                    if producto.product_id.expense_pdt:
                        print producto.product_id.name
                        flag = True
                if flag:
                    totali -= (order.amount_total * 2)

            total = (totali - totalf)
            res[session.id] = total

            if total < 0:
                total = -total
            else:
                total = -total

            if session.state != 'closed':
                self.write(cr, uid, session.id, {'difference2': total}, context=context)
                self.write(cr, uid, session.id, {'money_close': totali}, context=context)
                self.write(cr, uid, session.id, {'money_reported': totalf}, context=context)
        return res

    def _calc_vb(self, cr, uid, ids, fields, args, context=None):
        res = {}
        flag = False
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            for order in session.order_ids:
                flag = False
                for producto in order.lines:
                    if producto.product_id.expense_pdt or producto.product_id.income_pdt:
                        flag = True
                if not flag:
                    total += order.amount_total
            res[session.id] = total
        return res

    def _calc_statements_total(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            for st in session.statement_ids:
                total += st.total_entry_encoding_custom
            res[session.id] = total
        return res

    def _calc_isv(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            for order in session.order_ids:
                total += order.amount_tax
            res[session.id] = total
        return res

    def _calc_subtotal(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = session.venta_bruta - session.isv
            res[session.id] = total
        return res

    def _calc_no_facturas(self, cr, uid, ids, fields, args, context=None):
        res = {}
        array = []
        count = 0
        for session in self.browse(cr, uid, ids, context=context):
            for order in session.order_ids:
                count += 1
                array.append(order.pos_reference)
            if array:
                res[session.id] = str(count) + " facturas " + str(array[len(array) - 1]) + " A " + str(array[0])

        return res

    def _calc_discount(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            des_total = 0
            for order in session.order_ids:
                discount = 0
                for desc in order.lines:
                    discount += desc.price_unit * (desc.discount / 100)
                des_total += discount
            res[session.id] = des_total
        return res

    def _calc_money_incoming(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            counttotal = 0

            for order in session.order_ids:
                total2 = 0
                count = 0
                for desc in order.lines:
                    if desc.product_id.income_pdt:
                        count += 1
                        total2 += desc.price_subtotal_incl
                total += total2
                counttotal += count
            res[session.id] = str(counttotal) + " Entrada(s) " + " Total Entradas " + str(total)
        return res

    def _calc_money_outgoing(self, cr, uid, ids, fields, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            total = 0
            counttotal = 0
            for order in session.order_ids:
                total2 = 0
                count = 0
                for desc in order.lines:
                    if desc.product_id.expense_pdt:
                        count += 1
                        total2 += desc.price_subtotal_incl
                total += total2
                counttotal += count
            res[session.id] = str(counttotal) + " Salida(s) " + "  Total Salidas " + str(total)
        return res

    def _calc_tickets(self, cr, uid, ids, name, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = {
                'tickets_num': 0,
                'ticket_first_id': None,
                'ticket_last_id': None,
            }
            if session.order_ids:
                res[session.id]['tickets_num'] = len(session.order_ids)
                res[session.id]['ticket_first_id'] = session.order_ids[-1]
                res[session.id]['ticket_last_id'] = session.order_ids[0]
        return res

    def summary_by_product(self, cr, uid, ids, context=None):
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        products = {}  # product_id -> data
        for session in self.browse(cr, uid, ids, context=context):
            for order in session.order_ids:
                for line in order.lines:
                    id = line.product_id.id
                    if id not in products:
                        products[id] = {'product': line.product_id.name,
                                        'qty': 0,
                                        'total': 0}
                    products[id]['qty'] += line.qty
                    products[id]['total'] += line.price_subtotal_incl
        return products.values()

    def summary_by_tax(self, cr, uid, ids, context=None):
        assert len(ids) == 1, 'This option should only be used for a single id at a time.'
        account_tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        res = {}  # tax_id -> data
        for session in self.browse(cr, uid, ids, context=context):
            for order in session.order_ids:
                for line in order.lines:
                    taxes_ids = [tax.id for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id]

                    price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
                    cur = line.order_id.pricelist_id.currency_id
                    taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, cur.id, line.qty, line.product_id.id, line.order_id.partner_id.id or False)

                    print 'taxes', taxes
                    for tax in taxes['taxes']:
                        id = tax['id']
                        if id not in res:
                            t = account_tax_obj.browse(cr, uid, id, context=context)
                            tax_rule = ''
                            if t.amount_type == 'percent':
                                tax_rule = str(100 * t.amount) + '%'
                            else:
                                tax_rule = str(t.amount)
                            res[id] = {'name': tax['name'],
                                       'base': 0,
                                       'tax': tax_rule,
                                       'total': 0,
                                       }
                        #res[id]['base'] += cur.round(tax['price_unit'] * line.qty)
                        res[id]['base'] += cur.round(taxes['total_excluded'])
                        res[id]['total'] += tax['amount']
                        # cur_obj.round(cr, uid, cur, taxes['amount'])

        return res.values()

    def _calc_tax(self, cr, uid, ids, name, args, context=None):
        account_tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = {'tax_base_total': 0}
            for order in session.order_ids:
                for line in order.lines:
                    taxes_ids = [tax for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id]

                    price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
                    taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, line.qty, product=line.product_id, partner_id=line.order_id.partner_id.id or False)
                    cur = line.order_id.pricelist_id.currency_id

                    res[session.id]['tax_base_total'] += taxes['total']
        return res

    def _calc_sales(self, cr, uid, ids, name, args, context=None):
        res = {}
        for session in self.browse(cr, uid, ids, context=context):
            res[session.id] = {'untaxed_sales': 0}
            for order in session.order_ids:
                for line in order.lines:
                    if not line.product_id.taxes_id:
                        res[session.id]['untaxed_sales'] += line.price_subtotal
        return res

    _inherit = 'pos.session'

    cash_register_total_entry_encoding_custom = fields.Float(related='cash_register_id.total_entry_encoding_custom',
                                                                    string='Total Sales',
                                                                    readonly=True,
                                                                    )
    cash_register_total_entry_encoding_put_in = fields.Float(related='cash_register_id.total_entry_encoding_put_in',
                                                                    string='Cash put in',
                                                                    readonly=True,
                                                                    )
    cash_register_total_entry_encoding_take_out = fields.Float(related='cash_register_id.total_entry_encoding_take_out',
                                                                      string='Cash take out',
                                                                      readonly=True,
                                                                      )


        #'validate':fields.Boolean(string="Validation",help="validation"),
        #'difference':fields.Function(_fun_difference,string="Difference"),
        #'difference2':fields.Float('difference2'),
        #'venta_bruta':fields.Function(_calc_vb,'Venta bruta', help='Gross sales'),
        #'isv':fields.Function(_calc_isv,'ISV'),
        #'subtotal':fields.Function(_calc_subtotal,'subtotal'),
        #'nro_facturas':fields.Char(compute="_calc_no_facturas",'nro facturas',),
        #'discount':fields.Function(_calc_discount,'discount'),
        #'tax_base_total':fields.Function(_calc_tax,'Total Sales without taxes',),
    untaxed_sales = fields.Float(compute=_calc_sales, string='Untaxed sales',)
        #'money_incoming':fields.Char(compute="_calc_money_incoming",'money incoming',),
        #'money_outgoing':fields.Char(compute="_calc_money_outgoing",'money outgoing',),
    statements_total = fields.Float(compute=_calc_statements_total, string='Total Payments Received')
    tickets_num = fields.Integer(compute="_calc_tickets", string='Number of Tickets',)
    ticket_first_id = fields.Many2one('pos.order', compute="_calc_tickets", string='First Ticket',)
    ticket_last_id = fields.Many2one('pos.order', compute="_calc_tickets", string='Last Ticket',)
Beispiel #18
0
class MrpProduction(models.Model):

    _inherit = "mrp.production"

    goods_request_date = fields.Date('Request date')
    goods_return_date = fields.Date('Return date')
    picking_notes = fields.Text('Picking notes')
    hoard_ids = fields.One2many('stock.picking',
                                string='hoards',
                                compute='_get_hoard_picking')
    hoard_len = fields.Integer('hoard len', compute='_get_hoard_len')
    hoard_need_assignment = fields.Boolean('Hoard needs assignement',
                                           compute='_get_hoard_assigned')
    workcenter_lines = fields.One2many(readonly=False)

    @api.one
    @api.depends('hoard_ids')
    def _get_hoard_len(self):
        self.hoard_len = len(self.hoard_ids)

    @api.one
    @api.depends('hoard_ids')
    def _get_hoard_assigned(self):
        need_assignement = False
        for hoard in self.hoard_ids:
            if hoard.state in ('confirmed', 'partially_available'):
                need_assignement = True
        self.hoard_need_assignment = need_assignement

    @api.one
    @api.depends('move_lines.move_orig_ids', 'move_lines2.move_orig_ids')
    def _get_hoard_picking(self):
        pickings = self.env['stock.picking']
        pickings += self.mapped('move_lines.move_orig_ids.picking_id').sorted(
        ) | self.mapped('move_lines2.move_orig_ids.picking_id').sorted()
        self.hoard_ids = pickings

    @api.multi
    def action_assign_hoard(self):
        for prod in self:
            prod.hoard_ids.action_assign()

    def _create_previous_move(self,
                              cr,
                              uid,
                              move_id,
                              product,
                              source_location_id,
                              dest_location_id,
                              context=None):
        if not context:
            context = {}
        proc_obj = self.pool.get('procurement.group')
        move = super(MrpProduction,
                     self)._create_previous_move(cr, uid, move_id, product,
                                                 source_location_id,
                                                 dest_location_id, context)
        prod_name = context.get('production', False)
        move_dict = {'workcenter_id': context.get('workcenter_id', False)}
        if prod_name:
            procurement = proc_obj.search(cr,
                                          uid, [('name', '=', prod_name)],
                                          context=context)
            if not procurement:
                procurement = proc_obj.create(cr, uid, {'name': prod_name},
                                              context)
            else:
                procurement = procurement[0]
            move_dict['group_id'] = procurement
        self.pool.get('stock.move').write(cr,
                                          uid,
                                          move,
                                          move_dict,
                                          context=context)
        return move

    @api.multi
    def get_hoard(self):
        action = self.env.ref('stock.action_picking_tree')
        if not action:
            return
        action = action.read()[0]
        res = self.env.ref('stock.view_picking_form')
        action['views'] = [(res.id, 'form')]
        action['res_id'] = self.hoard_ids and self.hoard_ids[0].id or False
        action['context'] = False
        return action

    def action_cancel(self, cr, uid, ids, context=None):
        """ Cancels the production order and related stock moves.
        @return: True
        """
        if context is None:
            context = {}
        move_obj = self.pool.get('stock.move')
        proc_obj = self.pool.get('procurement.order')
        for production in self.browse(cr, uid, ids, context=context):
            if production.move_created_ids:
                move_obj.action_cancel(
                    cr, uid, [x.id for x in production.move_created_ids])
            moves = move_obj.search(
                cr,
                uid,
                [('move_dest_id', 'in', [x.id
                                         for x in production.move_lines])],
                context=context)
            if moves:
                move_ids = []
                for move in move_obj.browse(cr, uid, moves, context):
                    if move.state not in ('cancel', 'done'):
                        move_ids.append(move.id)
                move_obj.action_cancel(cr, uid, move_ids, context=context)
            move_obj.action_cancel(cr, uid,
                                   [x.id for x in production.move_lines])
        self.write(cr, uid, ids, {'state': 'cancel'})
        # Put related procurements in exception
        proc_obj = self.pool.get("procurement.order")
        procs = proc_obj.search(cr,
                                uid, [('production_id', 'in', ids)],
                                context=context)
        if procs:
            proc_obj.write(cr,
                           uid,
                           procs, {'state': 'exception'},
                           context=context)
        return True

    @api.model
    def _make_consume_line_from_data(self, production, product, uom_id, qty,
                                     uos_id, uos_qty):
        my_context = dict(self.env.context)
        my_context['production'] = production.name
        return super(
            MrpProduction,
            self.with_context(my_context))._make_consume_line_from_data(
                production, product, uom_id, qty, uos_id, uos_qty)

    def _make_production_consume_line(self, cr, uid, line, context=None):
        context = dict(context)
        context['workcenter_id'] = line.workcenter_id.id
        move_id = super(MrpProduction, self)._make_production_consume_line(
            cr, uid, line, context)
        self.pool.get('stock.move').write(
            cr, uid, move_id, {'workcenter_id': line.workcenter_id.id},
            context)
        return move_id

    @api.multi
    def create_continuation(self):
        protocol_type = self.env['protocol.type'].search([('is_continuation',
                                                           '=', True)])
        if not protocol_type:
            raise exceptions.Warning(_('Protocol error'),
                                     _('continuation protocol type not found'))
        assert len(protocol_type.workcenter_ids) == 1
        workcenter_line_dict = {
            'name':
            protocol_type.name + ' ' + date.today().strftime('%d-%m-%Y') +
            ' - ' + self.product_id.name,
            'production_id':
            self.id,
            'workcenter_id':
            protocol_type.workcenter_ids[0].id,
            'date_planned':
            date.today(),
            'continuation':
            True
        }
        self.env['mrp.production.workcenter.line'].create(workcenter_line_dict)
class PricelistOffer(models.Model):
    _name = 'product.pricelist.item.offer'

    name = fields.Char(string='Offer Name')
    paid_qty = fields.Integer(string='Paid quantity')
    free_qty = fields.Integer(string='Free quantity')
Beispiel #20
0
class RMAConfigSettings(models.TransientModel):
    _name = 'rma.config.settings'
    _inherit = 'res.config.settings'

    @api.constrains("priority_maximum", "priority_maximum")
    def _check_priority_config(self):
        for company_id in self:
            priority_max = company_id.priority_maximum
            priority_min = company_id.priority_minimum
            if priority_min <= 0 or priority_max <= 0:
                raise ValidationError(
                    _("Priority maximum and priority_minimum must "
                      "be greater than zero"))
            if priority_max >= priority_min:
                raise ValidationError(
                    _("Priority maximum must be less than priority_minimum"))

    @api.constrains("limit_days")
    def _check_limit_days_config(self):
        company_ids = self.filtered(lambda r: r.limit_days <= 0)
        if company_ids:
            raise ValidationError(_("Limit days must be greater than zero"))

    limit_days = fields.Integer(
        help="Limit days for resolving a claim since its creation date.")
    priority_maximum = fields.Integer(
        help="Priority of a claim should be:\n"
        "- Very High: Purchase date <= priority maximum range.\n"
        "- High: priority maximum range < invoice date <= "
        "priority minimun range")
    priority_minimum = fields.Integer(
        help="Priority of a claim should be:\n"
        "- High: priority maximum range < invoice date "
        "<= priority minimun range.\n"
        "- Normal: priority minimun range < invoice date")

    @api.multi
    def get_default_rma_values(self):
        """Get the current company rma configuration and
        show into the config
        wizard.
        @return dictionary with the values to display.
        """
        company_id = self.env.user.company_id
        return {
            "limit_days": company_id.limit_days,
            "priority_maximum": company_id.priority_maximum,
            "priority_minimum": company_id.priority_minimum,
        }

    @api.multi
    def set_rma_config(self):
        """Write the rma configuratin in the wizard into the company model.
        @return True
        """
        company_id = self.env.user.company_id
        for rma_config in self:
            company_id.write({
                "limit_days": rma_config.limit_days,
                "priority_maximum": rma_config.priority_maximum,
                "priority_minimum": rma_config.priority_minimum,
            })
        return True
Beispiel #21
0
class employee(models.Model):
    """ 
    Employee 
    """
    _name = 'employee'
    _description = 'Employee'

    @api.multi
    @api.depends('name')
    def name_get(self):
        """
            On affiche prenom nom
        """
        result = []
        for employee_rcs in self:
            name = '%s %s' % (employee_rcs.first_name, employee_rcs.name)
            result.append((employee_rcs.id, name))

        return result

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=1000):
        """
            Fonction name_search
        """
        recs = self.search(
            ['|', ('name', operator, name),
             ('first_name', 'ilike', name)] + args,
            limit=limit)
        return recs.name_get()

    @api.model
    def _state_get(self):
        return [
            ('future', _('Future')),
            ('active', _('Active')),
            ('old', _('Old')),
        ]

    @api.one
    def _get_picture_binary_filesystem(self):
        attachment_obj = self.env['ir.attachment']
        attachment_rs = attachment_obj.search([('res_model', '=', self._name),
                                               ('res_id', '=', self.id),
                                               ('binary_field', '=', 'picture')
                                               ])
        if attachment_rs:
            self['picture'] = attachment_rs[0].datas

    @api.one
    def _set_picture_binary_filesystem(self):
        attachment_obj = self.env['ir.attachment']
        attachment_rs = attachment_obj.search([('res_model', '=', self._name),
                                               ('res_id', '=', self.id),
                                               ('binary_field', '=',
                                                'picture'),
                                               ('is_binary_field', '=', True)])
        if self.picture:
            if attachment_rs:
                attachment_rs.datas = self.picture
            else:
                attachment_obj.create({
                    'res_model': self._name,
                    'res_id': self.id,
                    'name': 'picture datas',
                    'is_binary_field': True,
                    'binary_field': 'picture',
                    'datas': self.picture,
                    'datas_fname': 'picture datas'
                })
        else:
            attachment_rs.unlink()

    @api.model
    def _family_situation_get(self):
        return [
            ('single', _('Single')),
            ('married', _('Married')),
            ('divorced', _('Divorced')),
            ('widowed', _('Widowed')),
        ]

    @api.model
    def _type_sex_get(self):
        return [
            ('female', _('Female')),
            ('male', _('Male')),
        ]

    @api.one
    @api.depends('birth_date')
    def _compute_age(self):
        age = 0
        if self.birth_date:
            age = relativedelta(datetime.now(),
                                datetime.strptime(self.birth_date,
                                                  "%Y-%m-%d")).years

        self.age = age

    #===========================================================================
    # COLUMNS
    #===========================================================================
    # Entete
    name = fields.Char(required=True, size=256)
    state = fields.Selection('_state_get',
                             string='State',
                             default='future',
                             required=True)
    first_name = fields.Char(string="First name", required=True, size=256)
    resource_id = fields.Many2one('mrp.resource',
                                  string='Resource',
                                  required=False,
                                  ondelete='restrict')
    account_id = fields.Many2one('account.account',
                                 string='Account',
                                 required=True,
                                 ondelete='restrict')
    company_id = fields.Many2one('res.company',
                                 string='Company',
                                 required=True,
                                 ondelete='restrict',
                                 default=lambda self: self.env.user.company_id)
    picture = fields.Binary(string='Picture',
                            compute='_get_picture_binary_filesystem',
                            inverse='_set_picture_binary_filesystem',
                            help='help')
    is_responsible = fields.Boolean(string='Responsible', default=False)
    calendar_id = fields.Many2one(
        'calendar',
        string='Calendar',
        required=True,
        ondelete='restrict',
        help='Come from the selected resource or manually selected')
    category_id = fields.Many2one('employee.category',
                                  string='Category',
                                  required=True,
                                  ondelete='restrict')
    # Information personnelle
    address_id = fields.Many2one('address',
                                 string='Address',
                                 required=True,
                                 ondelete='restrict')
    age = fields.Integer(string='Age', compute='_compute_age')
    nationality_id = fields.Many2one('res.country',
                                     string='Nationality',
                                     required=False,
                                     ondelete='restrict')
    civility_id = fields.Many2one('res.partner.title',
                                  string='Civility',
                                  required=False,
                                  ondelete='restrict')
    phone = fields.Char(string='Phone', size=20, required=False)
    email = fields.Char(string='Email', size=128, required=False)
    identity_number = fields.Char(string='Identity number',
                                  size=128,
                                  required=False)
    passport_number = fields.Char(string='Passport number',
                                  size=128,
                                  required=False)
    birth_date = fields.Date(string='Birth date')
    account_bank_id = fields.Many2one('res.partner.bank',
                                      string='Account bank',
                                      required=False,
                                      ondelete='restrict')
    place_birth = fields.Char(string='Place of birth',
                              size=256,
                              required=False)
    contact_name = fields.Char(string='Contact name', size=256, required=False)
    relationship_contact = fields.Char(string='Relationship with the contact',
                                       size=256,
                                       required=False)
    contact_phone = fields.Char(string='Contact phone',
                                size=20,
                                required=False)
    specific_note_contact = fields.Text(string='Specific note contact')
    family_situation = fields.Selection('_family_situation_get',
                                        string='Family situation')
    type_sex = fields.Selection('_type_sex_get', string='Type of sex')
    children_ids = fields.One2many('employee.children',
                                   'employee_id',
                                   string='Children')
    # Information RH
    entry_date = fields.Date(string='Entry date')
    release_date = fields.Date(string='Release date')
    employee_number = fields.Char(string='Employee number',
                                  size=256,
                                  required=False)
    degree_id = fields.Many2one('employee.degree',
                                string='Degree',
                                required=False,
                                ondelete='restrict')
    office_id = fields.Many2one('employee.office',
                                string='Office',
                                required=False,
                                ondelete='restrict')
    responsible_id = fields.Many2one('employee',
                                     string='Responsible',
                                     required=False,
                                     ondelete='restrict',
                                     domain=[('is_responsible', '=', True)])
    service_id = fields.Many2one('employee.service',
                                 string='Service',
                                 required=False,
                                 ondelete='restrict')
    note_hr = fields.Text(string='Note HR')
    avg_hour = fields.Float(
        string='Average hours',
        default=0.0,
        required=False,
        help=
        "The average work hours of the employee (used to help for input the holidays )"
    )

    #===========================================================================
    # Contraintes
    #===========================================================================
    @api.one
    @api.constrains('resource_id', 'calendar_id')
    def _check_calendar_resource(self):
        """
            Si l'employé est lié à une resource, son calendrier doit être le même
            que celui de la ressource 
        """
        if self.resource_id:
            if self.calendar_id != self.resource_id.calendar_id:
                raise Warning(
                    _("If your employee is linked to a resource, he must have the same calendar than the resource"
                      ))

    #===========================================================================
    # Onchanges
    #===========================================================================
    @api.onchange('resource_id')
    def _onchange_resource_id(self):
        """
            On ramène le calendrier de la resource sélectionnée
        """
        calendar_id = False
        if self.resource_id:
            calendar_id = self.resource_id.calendar_id and self.resource_id.calendar_id.id or False

        self.calendar_id = calendar_id

    #===========================================================================
    # Fonction
    #===========================================================================
    @api.model
    def create(self, vals):
        """
            Test pour ne pas avoir deux employés avec la même resource sauf si old
        """
        employee_rcs = super(employee, self).create(vals)
        if employee_rcs.resource_id:
            employee_search_rcs = self.search([('resource_id', '=',
                                                employee_rcs.resource_id.id),
                                               ('state', '!=', 'old'),
                                               ('id', '!=', employee_rcs.id)])
            if employee_search_rcs:
                raise except_orm(
                    _('Error'),
                    _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)."
                      ) % (employee_search_rcs[0].first_name,
                           employee_search_rcs[0].name))

        return employee_rcs

    @api.multi
    def write(self, vals):
        """
            Test pour ne pas avoir deux employés avec la même resource sauf si old
        """
        for employee_rc in self:
            if vals and 'resource_id' in vals and vals['resource_id'] and (
                ('state' not in vals and employee_rc.state != 'old') or
                ('state' in vals and vals['state'] != 'old')):
                if len(self.ids) > 1:
                    raise except_orm(
                        _('Error'),
                        _('It is not possible to have more employees with the same resource with different old of state'
                          ))

                employee_rcs = self.search([('resource_id', '=',
                                             vals['resource_id']),
                                            ('state', '!=', 'old')])
                if employee_rcs:
                    raise except_orm(
                        _('Error'),
                        _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)."
                          ) %
                        (employee_rcs[0].first_name, employee_rcs[0].name))

            elif 'state' in vals and vals['state'] != 'old':
                employee_rcs = self.search([('resource_id', '=',
                                             employee_rc.resource_id.id),
                                            ('state', '!=', 'old'),
                                            ('id', '!=', employee_rc.id)])
                if employee_rcs:
                    raise except_orm(
                        _('Error'),
                        _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)."
                          ) %
                        (employee_rcs[0].first_name, employee_rcs[0].name))

        return super(employee, self).write(vals)
class clv_batch_category(models.Model):
    _name = 'clv_batch.category'

    name = fields.Char('Category', required=True, size=64, translate=True)
    parent_id = fields.Many2one('clv_batch.category', 'Parent Category', select=True, ondelete='restrict')
    code = fields.Char ('Category Code',size=128, required=False)
    description = fields.Char(string='Description', size=256)
    notes = fields.Text(string='Notes')
    complete_name = fields.Char(string='Full Category', compute='_name_get_fnc', store=False, readonly=True)
    child_ids = fields.One2many('clv_batch.category', 'parent_id', 'Child Categories')
    active = fields.Boolean('Active', 
                            help="If unchecked, it will allow you to hide the category without removing it.",
                            default=1)
    parent_left = fields.Integer('Left parent', select=True)
    parent_right = fields.Integer('Right parent', select=True)
    batch_ids = fields.Many2many('clv_batch', 
                                 'clv_batch_category_rel', 
                                 'category_id', 
                                 'batch_id', 
                                 'Batches')

    _sql_constraints = [
        ('uniq_category_code', 'unique(code)', "Error! The Category Code must be unique!"),
        ]

    _constraints = [
        (models.Model._check_recursion, 'Error! You can not create recursive categories.', ['parent_id'])
        ]
    
    _parent_store = True
    _parent_order = 'name'
    _order = 'parent_left'

    @api.multi
    def name_get(self):
        """Return the category's display name, including their direct parent by default.

        :param dict context: the ``category_display`` key can be
                             used to select the short version of the
                             category (without the direct parent),
                             when set to ``'short'``. The default is
                             the long version."""
        if self._context is None:
            self._context = {}
        if self._context.get('category_display') == 'short':
            return super(clv_category, self).name_get()
        if isinstance(self._ids, (int, long)):
            self._ids = [self._ids]
        reads = self.read(['name', 'parent_id'])
        res = []
        for record in reads:
            name = record['name']
            if record['parent_id']:
                name = record['parent_id'][1] + ' / ' + name
            res.append((record['id'], name))
        return res

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=100):
        args = args or []
        if name:
            name = name.split(' / ')[-1]
            args = [('name', operator, name)] + args
        categories = self.search(args, limit=limit)
        return categories.name_get()


    @api.multi
    def _name_get_fnc(self, field_name, arg):
        return dict(self.name_get())

    @api.one
    def _name_get_fnc(self):
        self.refresh_complete_name = 0
        complete_name =  self.name_get()
        if complete_name:
            self.complete_name = complete_name[0][1]
        else:
            self.complete_name = self.name
Beispiel #23
0
class ResPartner(models.Model):
    _inherit = "res.partner"

    @api.multi
    @api.depends('capital_certificate_ids')
    def _compute_capital_certificate_count(self):
        for partner in self:
            partner.capital_certificate_count = len(
                partner.capital_certificate_ids)

    capital_certificate_ids = fields.One2many(
        string="Capital Certificates",
        comodel_name="capital.certificate",
        inverse_name="partner_id")
    capital_certificate_count = fields.Integer(
        string="Capital Certificates count",
        compute="_compute_capital_certificate_count")

    @api.multi
    def generate_certificate(self, year=False, send_mail=False):
        if not year:
            return False

        aml_obj = self.env['account.move.line']
        cc_obj = self.env['capital.certificate']
        mail_template = self.env.ref(
            "coop_capital_certificate.capital_certificate_mail_template")
        min_date = "%s-01-01" % (year)
        max_date = "%s-01-01" % (year + 1)

        cfc_obj = self.env['capital.fundraising.category']
        account_list = tuple(
            [c.capital_account_id.id for c in cfc_obj.search([])])
        for partner in self:
            lines = []
            aml_ids = aml_obj.search([
                ('partner_id', '=', partner.id),
                ('date', '>=', min_date),
                ('date', '<', max_date),
                ('account_id', 'in', account_list),
                ('credit', '>', 0),
            ],
                                     order='account_id')
            for aml in aml_ids:
                price = aml.product_id.list_price
                qty = aml.credit / price
                lines.append({
                    'account_move_line_id': aml.id,
                    'date': aml.invoice_id.date_invoice,
                    'qty': qty,
                    'product': aml.product_id.name,
                    'price': price,
                    'payment_date': aml.date,
                })

            lines = map(lambda x: (0, 0, x), lines)
            cc = cc_obj.create({
                'partner_id': partner.id,
                'year': year,
                'template_id': mail_template.id,
                'line_ids': lines,
            })
            cc.create_certificate(send_mail)
class StockInformation(models.Model):
    _name = 'stock.information'
    _description = 'Stock information'
    _order = 'company, location, product, first_day_week asc'

    @api.multi
    def _compute_week(self):
        orderpoint_obj = self.env['stock.warehouse.orderpoint']
        proc_obj = self.env['procurement.order']
        move_obj = self.env['stock.move']
        pur_line_obj = self.env['purchase.order.line']
        sale_line_obj = self.env['sale.order.line']
        for line in self:
            line.qty_available = 0
            line.minimum_rule = 0
            if line.product and line.location:
                cond = [('company_id', '=', line.company.id),
                        ('product_id', '=', line.product.id),
                        ('location_id', '=', line.location.id),
                        ('active', '=', True)]
                rule = orderpoint_obj.search(cond, limit=1)
                if rule:
                    line.minimum_rule = rule.product_min_qty
                if line.first_week:
                    prod = self.env['product.product'].with_context({
                        'location':
                        line.location.id
                    }).browse(line.product.id)
                    line.qty_available = prod.qty_available
                else:
                    year = line.year
                    week = line.week - 1
                    if line.week == 1:
                        year -= 1
                        new_date = str(year) + '-12-31'
                        new_date = fields.Datetime.from_string(new_date).date()
                        week = new_date.strftime('%W')
                    cond = [('company', '=', line.company.id),
                            ('year', '=', year), ('week', '=', week),
                            ('location', '=', line.location.id),
                            ('product', '=', line.product.id)]
                    prev = self.search(cond, limit=1)
                    if (prev.stock_availability >=
                            prev.outgoing_pending_amount):
                        line.qty_available = (prev.stock_availability +
                                              line.minimum_rule -
                                              prev.outgoing_pending_amount)
                    else:
                        line.qty_available = line.minimum_rule
            if line.first_week:
                moves = move_obj._find_moves_from_stock_information(
                    line.company,
                    line.last_day_week,
                    products=[line.product.id],
                    location_dest_id=line.location)
            else:
                moves = move_obj._find_moves_from_stock_information(
                    line.company,
                    line.last_day_week,
                    products=[line.product.id],
                    from_date=line.first_day_week,
                    location_dest_id=line.location)
            line.incoming_pending_amount = sum(moves.mapped('product_uom_qty'))
            line.incoming_pending_moves = [(6, 0, moves.ids)]
            moves = moves.filtered(lambda x: x.purchase_line_id)
            purchase_orders = self.env['purchase.order']
            purchase_orders |= moves.mapped('purchase_line_id.order_id')
            line.incoming_pending_purchases = [(6, 0, purchase_orders.ids)]
            if line.first_week:
                moves = move_obj._find_moves_from_stock_information(
                    line.company,
                    line.last_day_week,
                    products=[line.product.id],
                    location_id=line.location)
            else:
                moves = move_obj._find_moves_from_stock_information(
                    line.company,
                    line.last_day_week,
                    products=[line.product.id],
                    from_date=line.first_day_week,
                    location_id=line.location)
            line.outgoing_pending_amount = sum(moves.mapped('product_uom_qty'))
            line.outgoing_pending_moves = [(6, 0, moves.ids)]
            states = ['confirmed', 'exception']
            if line.first_week:
                procs = proc_obj._find_procurements_from_stock_information(
                    line.company,
                    line.last_day_week,
                    states=states,
                    products=[line.product.id],
                    location_id=line.location)
            else:
                procs = proc_obj._find_procurements_from_stock_information(
                    line.company,
                    line.last_day_week,
                    states=states,
                    from_date=line.first_day_week,
                    products=[line.product.id],
                    location_id=line.location)
            line.demand = sum(procs.mapped('product_qty'))
            procurement_orders = self.env['procurement.order']
            if procs:
                procurement_orders |= procs
            line.demand_procurements = [(6, 0, procurement_orders.ids)]
            if line.first_week:
                purchase_lines = (
                    pur_line_obj._find_purchase_lines_from_stock_information(
                        line.company, line.last_day_week, line.product,
                        line.location))
            else:
                purchase_lines = (
                    pur_line_obj._find_purchase_lines_from_stock_information(
                        line.company,
                        line.last_day_week,
                        line.product,
                        line.location,
                        from_date=line.first_day_week))
            line.draft_purchases_amount = sum(
                purchase_lines.mapped('product_qty'))
            purchase_orders = self.env['purchase.order']
            if purchase_lines:
                purchase_orders |= purchase_lines.mapped('order_id')
            line.draft_purchases = [(6, 0, purchase_orders.ids)]
            if line.first_week:
                sale_lines = (
                    sale_line_obj._find_sale_lines_from_stock_information(
                        line.company, line.last_day_week, line.product,
                        line.location))
            else:
                sale_lines = (
                    sale_line_obj._find_sale_lines_from_stock_information(
                        line.company,
                        line.last_day_week,
                        line.product,
                        line.location,
                        from_date=line.first_day_week))
            line.draft_sales_amount = sum(sale_lines.mapped('product_uom_qty'))
            sale_orders = self.env['sale.order']
            if sale_lines:
                sale_orders |= sale_lines.mapped('order_id')
            line.draft_sales = [(6, 0, sale_orders.ids)]
            line.stock_availability = (line.qty_available - line.minimum_rule +
                                       line.incoming_pending_amount)
            if line.stock_availability >= line.outgoing_pending_amount:
                line.virtual_stock = 0
            else:
                line.virtual_stock = (line.outgoing_pending_amount -
                                      line.stock_availability)

    @api.multi
    @api.depends('product', 'product.seller_ids')
    def _compute_product_info(self):
        for line in self:
            sequence = False
            for supplier in line.product.seller_ids:
                if not sequence or sequence and sequence > supplier.sequence:
                    sequence = supplier.sequence
                    line.supplier = supplier.name.id

    company = fields.Many2one(comodel_name='res.company',
                              string='Company',
                              select=True)
    year = fields.Integer(string='Year', select=True)
    week = fields.Integer(string='Week', select=True)
    first_week = fields.Boolean(string='First week', default=False)
    first_day_week = fields.Date(string='First day on week')
    last_day_week = fields.Date(string='Last day on week')
    location = fields.Many2one(comodel_name='stock.location',
                               string='Location',
                               translate=True,
                               select=True)
    product = fields.Many2one(comodel_name='product.product',
                              string='Product',
                              translate=True,
                              select=True)
    category = fields.Many2one(comodel_name='product.category',
                               string='category',
                               store=True,
                               related='product.categ_id')
    product_template = fields.Many2one(comodel_name='product.template',
                                       string='Product template',
                                       store=True,
                                       related='product.product_tmpl_id')
    route = fields.Many2one('stock.location.route', 'Product Type')
    supplier = fields.Many2one('res.partner',
                               'Supplier',
                               compute='_compute_product_info',
                               store=True)
    qty_available = fields.Float(
        string='Quantity On Hand',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Initial stock')
    minimum_rule = fields.Float(
        string='Minimum rule',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Minimum rule')
    incoming_pending_amount = fields.Float(
        'Incoming pending amount',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Incoming pending')
    incoming_pending_purchases = fields.Many2many(
        comodel_name='purchase.order',
        relation='rel_stock_info_incoming_pending_purchase',
        column1='stock_info_id',
        column2='purchase_id',
        string='Purchases',
        compute='_compute_week')
    incoming_pending_moves = fields.Many2many(
        comodel_name='stock.move',
        string='Moves incoming to date',
        relation='rel_stock_info_incoming_pending_move',
        column1='stock_info_id',
        column2='move_in_id',
        compute='_compute_week')
    stock_availability = fields.Float(
        'Stock availability (DPS)',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Stock availability')
    demand = fields.Float('Demand (D)',
                          compute='_compute_week',
                          digits=dp.get_precision('Product Unit of Measure'),
                          help='Demand')
    demand_required_run = fields.Float(
        'Procurements required run',
        related='demand',
        digits=dp.get_precision('Product Unit of Measure'),
        store=True)
    demand_procurements = fields.Many2many(
        comodel_name='procurement.order',
        string='Demand procurements',
        relation='rel_stock_info_demand_procurement',
        compute='_compute_week',
        column1='stock_info_id',
        column2='proc_id')
    draft_purchases_amount = fields.Float(
        'Draft purchases amount (INFO)',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Draft purchases amount')
    draft_purchases = fields.Many2many(
        comodel_name='purchase.order',
        string='Draft purchases',
        relation='rel_stock_info_draft_purchase',
        compute='_compute_week',
        column1='stock_info_id',
        column2='purchase_id')
    draft_sales_amount = fields.Float(
        'Draft sales amount (INFO)',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Draft sales amount')
    draft_sales = fields.Many2many(comodel_name='sale.order',
                                   string='Draft sales',
                                   relation='rel_stock_draft_sale',
                                   compute='_compute_week',
                                   column1='stock_info_id',
                                   column2='sale_id')
    outgoing_pending_amount = fields.Float(
        'Outgoing pending amount',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Gross requirement')
    outgoing_pending_moves = fields.Many2many(
        comodel_name='stock.move',
        string='Moves outgoing to date',
        relation='rel_stock_info_outgoing_pending_moves',
        column1='stock_info_id',
        column2='move_out_id',
        compute='_compute_week')
    virtual_stock = fields.Float(
        'Virtual stock',
        compute='_compute_week',
        digits=dp.get_precision('Product Unit of Measure'),
        help='Net requirement')
    virtual_stock_required_increase = fields.Float(
        'Virtual stock required increment',
        related='virtual_stock',
        digits=dp.get_precision('Product Unit of Measure'),
        store=True)

    def _calculate_first_day_week(self, date):
        found = False
        if date.weekday() == 0 or (date.day == 1 and date.month == 1):
            found = True
        while not found:
            date = date + relativedelta(days=-1)
            if date.weekday() == 0 or (date.day == 1 and date.month == 1):
                found = True
        return date.strftime('%Y-%m-%d')

    def _calculate_last_day_week(self, date):
        found = False
        if date.weekday() == 6 or (date.day == 31 and date.month == 12):
            found = True
        while not found:
            date = date + relativedelta(days=+1)
            if date.weekday() == 6 or (date.day == 31 and date.month == 12):
                found = True
        return date.strftime('%Y-%m-%d')

    def _generate_stock_information(self, wiz, product_datas):
        buy_route = self.env.ref('purchase.route_warehouse0_buy')
        for data in product_datas:
            datos_array = product_datas[data]
            from_date = fields.Date.context_today(self)
            from_date = self._calculate_first_day_week(
                fields.Datetime.from_string(from_date).date())
            from_date = fields.Date.from_string(from_date)
            to_date = self._calculate_last_day_week(
                fields.Datetime.from_string(wiz.to_date).date())
            to_date = fields.Date.from_string(to_date)
            first_week = True
            while from_date <= to_date:
                first = self._calculate_first_day_week(from_date)
                last = self._calculate_last_day_week(from_date)
                route_id = False
                if (datos_array['product'].route_ids and buy_route.id
                        in datos_array['product'].route_ids.ids):
                    route_id = buy_route.id
                vals = {
                    'company': wiz.company.id,
                    'location': datos_array['location'].id,
                    'product': datos_array['product'].id,
                    'route': route_id,
                    'year': from_date.year,
                    'week': from_date.strftime('%W'),
                    'first_day_week': first,
                    'last_day_week': last,
                    'first_week': first_week
                }
                if first_week:
                    vals['first_day_week'] = fields.Date.context_today(self)
                    first_week = False
                self.create(vals)
                from_date = fields.Date.to_string(from_date +
                                                  relativedelta(days=7))
                from_date = fields.Date.from_string(from_date)

    @api.multi
    def show_incoming_pending_purchases(self):
        self.ensure_one()
        return {
            'name': _('Purchase orders'),
            'view_type': 'form',
            "view_mode": 'tree,form,graph,calendar',
            'res_model': 'purchase.order',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.incoming_pending_purchases.ids)]
        }

    @api.multi
    def show_incoming_pending_moves(self):
        self.ensure_one()
        return {
            'name': _('Incoming pending stock moves'),
            'view_type': 'form',
            "view_mode": 'tree,form',
            'res_model': 'stock.move',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.incoming_pending_moves.ids)]
        }

    @api.multi
    def show_outgoing_pending_moves(self):
        self.ensure_one()
        return {
            'name': _('Outgoing pending stock moves'),
            'view_type': 'form',
            "view_mode": 'tree,form',
            'res_model': 'stock.move',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.outgoing_pending_moves.ids)]
        }

    @api.multi
    def show_demand_procurements(self):
        self.ensure_one()
        return {
            'name': _('Procurement orders in draft state'),
            'view_type': 'form',
            "view_mode": 'tree,form',
            'res_model': 'procurement.order',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.demand_procurements.ids)]
        }

    @api.multi
    def show_draft_purchases(self):
        self.ensure_one()
        return {
            'name': _('Purchase orders in draft state'),
            'view_type': 'form',
            "view_mode": 'tree,form,graph,calendar',
            'res_model': 'purchase.order',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.draft_purchases.ids)]
        }

    @api.multi
    def show_draft_sales(self):
        self.ensure_one()
        return {
            'name': _('Sale orders in draft state'),
            'view_type': 'form',
            "view_mode": 'tree,form,calendar,graph',
            'res_model': 'sale.order',
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', self.draft_sales.ids)]
        }
Beispiel #25
0
class wizard(models.TransientModel):
    _name = 'mail_move_message.wizard'

    def _model_selection(self):
        selection = []
        config_parameters = self.env['ir.config_parameter']
        model_names = config_parameters.get_param('mail_relocation_models')
        model_names = model_names.split(',') if model_names else []

        if 'default_message_id' in self.env.context:
            message = self.env['mail.message'].browse(
                self.env.context['default_message_id'])
            if message.model and message.model not in model_names:
                model_names.append(message.model)
            if message.moved_from_model and message.moved_from_model not in model_names:
                model_names.append(message.moved_from_model)
        if model_names:
            selection = [(m.model, m.display_name)
                         for m in self.env['ir.model'].search([('model', 'in',
                                                                model_names)])]

        return selection

    @api.model
    def default_get(self, fields_list):
        res = super(wizard, self).default_get(fields_list)

        model_fields = self.fields_get()
        if model_fields['model']['selection']:
            res['model'] = model_fields['model']['selection'] and model_fields[
                'model']['selection'][0][0]

        if 'message_id' in res:
            message = self.env['mail.message'].browse(res['message_id'])
            email_from = message.email_from
            parts = email_split(email_from.replace(' ', ','))
            if parts:
                email = parts[0]
                name = email_from[:email_from.index(email)].replace(
                    '"', '').replace('<', '').strip() or email_from
            else:
                name, email = email_from
            res['message_name_from'] = name
            res['message_email_from'] = email

            res['partner_id'] = message.author_id.id
            if message.author_id and self.env.uid not in [
                    u.id for u in message.author_id.user_ids
            ]:
                res['filter_by_partner'] = True
            if message.author_id and res.get('model'):
                res_id = self.env[res['model']].search([],
                                                       order='id desc',
                                                       limit=1)
                res['res_id'] = res_id and res_id[0].id

        res['uid'] = self.env.uid

        return res

    message_id = fields.Many2one('mail.message', string='Message')
    message_body = fields.Html(related='message_id.body',
                               string='Message to move',
                               readonly=True)
    message_from = fields.Char(related='message_id.email_from',
                               string='From',
                               readonly=True)
    message_subject = fields.Char(related='message_id.subject',
                                  string='Subject',
                                  readonly=True)
    message_moved_by_message_id = fields.Many2one(
        'mail.message',
        related='message_id.moved_by_message_id',
        string='Moved with',
        readonly=True)
    message_moved_by_user_id = fields.Many2one(
        'res.users',
        related='message_id.moved_by_user_id',
        string='Moved by',
        readonly=True)
    message_is_moved = fields.Boolean(string='Is Moved',
                                      related='message_id.is_moved',
                                      readonly=True)
    parent_id = fields.Many2one(
        'mail.message',
        string='Search by name',
    )
    model = fields.Selection(_model_selection, string='Model')
    res_id = fields.Integer(string='Record')
    can_move = fields.Boolean('Can move', compute='get_can_move')
    move_back = fields.Boolean(
        'MOVE TO ORIGIN',
        help='Move  message and submessages to original place')
    partner_id = fields.Many2one('res.partner', string='Author')
    filter_by_partner = fields.Boolean('Filter Records by partner')
    message_email_from = fields.Char()
    message_name_from = fields.Char()
    # FIXME message_to_read should be True even if current message or any his childs are unread
    message_to_read = fields.Boolean(related='message_id.to_read')
    uid = fields.Integer()

    @api.depends('message_id')
    @api.one
    def get_can_move(self):
        # message was not moved before OR message is a top message of previous move
        self.can_move = not self.message_id.moved_by_message_id or self.message_id.moved_by_message_id.id == self.message_id.id

    @api.onchange('move_back')
    def on_change_move_back(self):
        if not self.move_back:
            return
        self.parent_id = self.message_id.moved_from_parent_id
        model = self.message_id.moved_from_model
        if self.message_id.is_moved:
            self.model = model
            self.res_id = self.message_id.moved_from_res_id

    @api.onchange('parent_id', 'res_id', 'model')
    def update_move_back(self):
        model = self.message_id.moved_from_model
        self.move_back = self.parent_id == self.message_id.moved_from_parent_id \
                         and self.res_id == self.message_id.moved_from_res_id \
                         and (self.model == model or (not self.model and not model))

    @api.onchange('parent_id')
    def on_change_parent_id(self):
        if self.parent_id and self.parent_id.model:
            self.model = self.parent_id.model
            self.res_id = self.parent_id.res_id
        else:
            self.model = None
            self.res_id = None

    @api.onchange('model', 'filter_by_partner', 'partner_id')
    def on_change_partner(self):
        domain = {'res_id': []}
        if self.model and self.filter_by_partner and self.partner_id:
            fields = self.env[self.model].fields_get(False)
            contact_field = False
            for n, f in fields.iteritems():
                if f['type'] == 'many2one' and f['relation'] == 'res.partner':
                    contact_field = n
                    break
            if contact_field:
                domain['res_id'] = [(contact_field, '=', self.partner_id.id)]
        if self.model:
            res_id = self.env[self.model].search(domain['res_id'],
                                                 order='id desc',
                                                 limit=1)
            self.res_id = res_id and res_id[0].id
        else:
            self.res_id = None
        return {'domain': domain}

    @api.one
    def check_access(self):
        cr = self._cr
        uid = self.env.user.id
        operation = 'write'
        context = self._context

        if not (self.model and self.res_id):
            return True
        model_obj = self.pool[self.model]
        mids = model_obj.exists(cr, uid, [self.res_id])
        if hasattr(model_obj, 'check_mail_message_access'):
            model_obj.check_mail_message_access(cr,
                                                uid,
                                                mids,
                                                operation,
                                                context=context)
        else:
            self.pool['mail.thread'].check_mail_message_access(
                cr, uid, mids, operation, model_obj=model_obj, context=context)

    @api.multi
    def open_moved_by_message_id(self):
        message_id = None
        for r in self:
            message_id = r.message_moved_by_message_id.id
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'mail_move_message.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'views': [[False, 'form']],
            'target': 'new',
            'context': {
                'default_message_id': message_id
            },
        }

    @api.multi
    def move(self):
        for r in self:
            r.check_access()
            if not r.parent_id or not (r.parent_id.model == r.model
                                       and r.parent_id.res_id == r.res_id):
                #link with the first message of record
                parent = self.env['mail.message'].search(
                    [('model', '=', r.model), ('res_id', '=', r.res_id)],
                    order='id',
                    limit=1)
                r.parent_id = parent.id or None

            r.message_id.move(r.parent_id.id, r.res_id, r.model, r.move_back)

        if not (r.model and r.res_id):
            obj = self.pool.get('ir.model.data').get_object_reference(
                self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1]
            return {
                'type': 'ir.actions.client',
                'name': 'Archive',
                'tag': 'reload',
                'params': {
                    'menu_id': obj
                },
            }
        return {
            'name': _('Record'),
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': r.model,
            'res_id': r.res_id,
            'views': [(False, 'form')],
            'type': 'ir.actions.act_window',
        }

    @api.one
    def delete(self):
        self.message_id.unlink()
        return {}

    @api.model
    def create_partner(self, message_id, relation, partner_id,
                       message_name_from, message_email_from):
        model = self.env[relation]
        message = self.env['mail.message'].browse(message_id)
        if not partner_id and message_name_from:
            partner_id = self.env['res.partner'].with_context({
                'update_message_author':
                True
            }).create({
                'name': message_name_from,
                'email': message_email_from
            }).id

        context = {'partner_id': partner_id}
        if model._rec_name:
            context.update({'default_%s' % model._rec_name: message.subject})

        fields = model.fields_get()
        contact_field = False
        for n, f in fields.iteritems():
            if f['type'] == 'many2one' and f['relation'] == 'res.partner':
                contact_field = n
                break
        if contact_field:
            context.update({'default_%s' % contact_field: partner_id})
        return context

    @api.one
    def read_close(self):
        self.message_id.set_message_read(True)
        self.message_id.child_ids.set_message_read(True)
        return {'type': 'ir.actions.act_window_close'}
Beispiel #26
0
class account_invoice_cashs(models.Model):
    _name = "account.invoice"
    _inherit = "account.invoice"

    # @api.one
    # @api.depends(
    # 'state', 'currency_id', 'invoice_line_ids.price_subtotal',
    # 'move_id.line_ids.amount_residual',
    # 'move_id.line_ids.currency_id')
    # def _compute_residual(self):
    #     residual = 0.0
    #     residual_company_signed = 0.0
    #     sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
    #     for line in self.sudo().move_id.line_ids:
    #         if line.account_id.internal_type in ('receivable', 'payable'):
    #             residual_company_signed += line.amount_residual
    #             if line.currency_id == self.currency_id:
    #                 residual += line.amount_residual_currency if line.currency_id else line.amount_residual
    #             else:
    #                 from_currency = (line.currency_id and line.currency_id.with_context(
    #                     date=line.date)) or line.company_id.currency_id.with_context(date=line.date)
    #                 residual += from_currency.compute(line.amount_residual, self.currency_id)
    #     self.residual_company_signed = abs(residual_company_signed) * sign
    #
    #     #residual += self.cartage + self.labour
    #     self.residual_signed = abs(residual) * sign
    #     self.residual = abs(residual)
    #     digits_rounding_precision = self.currency_id.rounding
    #     if float_is_zero(self.residual, precision_rounding=digits_rounding_precision):
    #         self.reconciled = True
    #     else:
    #         self.reconciled = False

    @api.model
    def create(self, vals):
        #	vals = {}
        order_serch = self.env['account.invoice']
        if vals.get('cash_credit') == 'cash_invoice':
            vals['serial_number'] = self.env['ir.sequence'].get(
                'account.invoice.cashs') or '/'
            print "======vals['serial_number']=======", vals['serial_number']

        elif vals.get('cash_credit') == 'credit_invoice':
            vals['serial_number'] = self.env['ir.sequence'].get(
                'account.invoice.credits') or '/'
            print "======vals['serial_number']=======", vals['serial_number']

        return super(account_invoice_cashs, self).create(vals)

    @api.multi
    def write(self, vals):
        if vals.get('cash_credit') == 'cash_invoice':
            vals['serial_number'] = self.env['ir.sequence'].get(
                'account.invoice.cashs') or '/'
            print "======vals['serial_number']=======", vals['serial_number']

        elif vals.get('cash_credit') == 'credit_invoice':
            vals['serial_number'] = self.env['ir.sequence'].get(
                'account.invoice.credits') or '/'
            print "======vals['serial_number']=======", vals['serial_number']

        return super(account_invoice_cashs, self).write(vals)

    def _compute_amount(self):
        self.amount_untaxed = sum(line.price_subtotal
                                  for line in self.invoice_line_ids)
        self.amount_tax = sum(line.amount for line in self.tax_line_ids)
        self.amount_total = self.amount_untaxed + self.amount_tax + self.cartage + self.labour
        amount_total_company_signed = self.amount_total
        amount_untaxed_signed = self.amount_untaxed
        if self.currency_id and self.currency_id != self.company_id.currency_id:
            amount_total_company_signed = self.currency_id.compute(
                self.amount_total, self.company_id.currency_id)
            amount_untaxed_signed = self.currency_id.compute(
                self.amount_untaxed, self.company_id.currency_id)
        sign = self.type in ['in_refund', 'out_refund'] and -1 or 1
        self.amount_total_company_signed = amount_total_company_signed * sign
        self.amount_total_signed = self.amount_total * sign
        self.amount_untaxed_signed = amount_untaxed_signed * sign

    cartage = fields.Float(string='Cartage',
                           digits=dp.get_precision('Product Price'))
    labour = fields.Float(string='Labour',
                          digits=dp.get_precision('Product Price'))
    cash_credit = fields.Selection([('cash_invoice', 'Cash'),
                                    ('credit_invoice', 'Credit')],
                                   string='Mode Of Payment',
                                   required=False,
                                   copy=False)
    serial_number = fields.Char(string='Serial Number', copy=False)
    debit_sequence = fields.Integer(string='Debit Sequence')
    penalty_date = fields.Date(string='Penalty Date')

    # reconciled = fields.Boolean(string='Paid/Reconciled', store=True, readonly=True, compute='_compute_residual')
    # residual = fields.Monetary(string='Amount Due', compute='_compute_residual', store=True)
    # residual_signed = fields.Monetary(string='Amount Due', currency_field='currency_id', compute='_compute_residual',
    #                                   store=True)
    # residual_company_signed = fields.Monetary(string='Amount Due', currency_field='company_currency_id',
    #                                           compute='_compute_residual', store=True)

    @api.multi
    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()

            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)

            # here creating an additional journal entry if cartage and Labour Exist
            if inv.cartage or inv.labour:
                iml.append({
                    'type':
                    'src',
                    'name':
                    'Cartage And Labour',
                    'price':
                    -(inv.cartage + inv.labour),
                    'price_unit':
                    inv.cartage + inv.labour,
                    'account_id':
                    self.env['account.account'].search(
                        [('name', '=', 'Local Services')], limit=1).id,
                    'date_maturity':
                    inv.date_due,
                    'amount_currency':
                    diff_currency
                    and company_currency.with_context(ctx).compute(
                        inv.cartage + inv.labour, inv.currency_id),
                    'currency_id':
                    diff_currency and inv.currency_id.id,
                    'invoice_id':
                    inv.id,
                    'quantity':
                    1.0,
                })

            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.cartage + inv.labour,
                                         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] + company_currency.with_context(ctx).compute(
                            inv.cartage + inv.labour, inv.currency_id),
                        '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 + inv.cartage + inv.labour,
                    'account_id':
                    inv.account_id.id,
                    'date_maturity':
                    inv.date_due,
                    'amount_currency':
                    diff_currency and total_currency +
                    company_currency.with_context(ctx).compute(
                        inv.cartage + inv.labour, inv.currency_id),
                    'currency_id':
                    diff_currency and inv.currency_id.id,
                    'invoice_id':
                    inv.id
                })

            print "IML....", iml

            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

    @api.multi
    def invoice_print_custom(self):
        """ Print the invoice and mark it as sent, so that we can see more
            easily the next step of the workflow
        """
        self.ensure_one()
        self.sent = True
        return self.env['report'].get_action(
            self, 'invoice_cartage.report_invoice_list')
Beispiel #27
0
class FleetVehicle(models.Model):

    _inherit = 'fleet.vehicle'
   

    @api.model
    def create(self, vals):
        acount_obj=self.env['account.analytic.account']
        fleet_id = super(FleetVehicle, self).create(vals)
        account_id=acount_obj.create({'name':self._vehicle_name_get(fleet_id)})
        fleet_id.write({'analytic_account_id':account_id.id,'use_tasks':True,'use_issues':True})
        return fleet_id
     
    @api.multi
    def _count_vehicle_task(self):
        project_obj = self.env['project.project']
        self.task_count=len(project_obj.search([('analytic_account_id', '=', self.analytic_account_id.id)]).task_ids)

    @api.multi
    def _count_vehicle_issue(self):
        issue_obj = self.env['project.project']
        self.issue_count=len(issue_obj.search([('analytic_account_id', '=', self.analytic_account_id.id)]).issue_ids)

        
    @api.multi
    def write(self, vals):
        acount_obj=self.env['account.analytic.account']
        res = super(FleetVehicle, self).write(vals)
        if not self.analytic_account_id:
            account_id=acount_obj.create({'name':self._vehicle_name_get(self)})
            self.write({'analytic_account_id':account_id.id,'use_tasks':True,'use_issues':True})
        self.analytic_account_id.write({'name':self.name,'use_tasks':True,'use_issues':True})
        return res
    
    @api.multi
    def _vehicle_name_get(self,record):
        res = record.model_id.brand_id.name + '/' + record.model_id.name + '/' + record.license_plate
        return res

    @api.multi
    def action_view_alltasks(self):
        self.ensure_one()
        action = self.env.ref('project.act_project_project_2_project_task_all')
        domain=[('project_id.analytic_account_id', '=', self.analytic_account_id.id)]
        return {
            'name': action.name,
            'res_model': 'project.task',
            'help': action.help,
            'type': action.type,
            'view_type': action.view_type,
            'view_mode': action.view_mode,
            'views': action.views,
            'target': action.target,
            'domain': domain,
        }
	
    @api.multi
    def action_view_allissues(self):
        self.ensure_one()
        action = self.env.ref('project_issue.act_project_project_2_project_issue_all')
        domain=[('project_id.analytic_account_id', '=', self.analytic_account_id.id)]
        return {
            'name': action.name,
            'res_model': 'project.issue',
            'help': action.help,
            'type': action.type,
            'view_type': action.view_type,
            'view_mode': action.view_mode,
            'views': action.views,
            'target': action.target,
            'domain': domain,
        }	

    analytic_account_id = fields.Many2one('account.analytic.account',string='Analytic Account')
    task_count = fields.Integer(compute=_count_vehicle_task, string="Vehicle Tasks" , multi=True)
    issue_count = fields.Integer(compute=_count_vehicle_issue, string="Vehicle Issues" , multi=True)
Beispiel #28
0
class CodaAccountMappingRule(models.Model):
    _name = 'coda.account.mapping.rule'
    _description = 'Rules Engine to assign accounts during CODA parsing'
    _order = 'sequence'

    coda_bank_account_id = fields.Many2one('coda.bank.account',
                                           string='CODA Bank Account',
                                           ondelete='cascade')
    sequence = fields.Integer(
        string='Sequence',
        default=10,
        help='Determines the order of the rules to assign accounts')
    name = fields.Char(string='Rule Name', required=True)
    active = fields.Boolean(string='Active',
                            default=True,
                            help='Switch on/off this rule.')
    # matching criteria
    trans_type_id = fields.Many2one('account.coda.trans.type',
                                    string='Transaction Type')
    trans_family_id = fields.Many2one('account.coda.trans.code',
                                      string='Transaction Family',
                                      domain=[('type', '=', 'family')])
    trans_code_id = fields.Many2one('account.coda.trans.code',
                                    'Transaction Code',
                                    domain=[('type', '=', 'code')])
    trans_category_id = fields.Many2one('account.coda.trans.category',
                                        string='Transaction Category')
    partner_id = fields.Many2one(
        'res.partner',
        string='Partner',
        ondelete='cascade',
        domain=['|', ('parent_id', '=', False), ('is_company', '=', True)])
    freecomm = fields.Char(string='Free Communication', size=128)
    struct_comm_type_id = fields.Many2one(
        'account.coda.comm.type', string='Structured Communication Type')
    structcomm = fields.Char(string='Structured Communication', size=128)
    payment_reference = fields.Char(
        string='Payment Reference',
        size=35,
        help="Payment Reference. For SEPA (SCT or SDD) transactions, "
        "the EndToEndReference is recorded in this field.")
    # results
    account_id = fields.Many2one('account.account',
                                 string='Account',
                                 ondelete='cascade',
                                 required=True,
                                 domain=[('type', '!=', 'view')])
    tax_code_id = fields.Many2one('account.tax.code',
                                  string='Tax Case',
                                  ondelete='cascade')
    analytic_account_id = fields.Many2one('account.analytic.account',
                                          string='Analytic Account',
                                          ondelete='set null',
                                          domain=[('type', '!=', 'view'),
                                                  ('state', 'not in',
                                                   ('close', 'cancelled'))])

    def _rule_select_extra(self, coda_bank_account_id):
        """
        Use this method to customize the mapping rule engine.
        Cf. l10n_be_coda_analytic_plan module for an example.
        """
        return ''

    def _rule_result_extra(self, coda_bank_account_id):
        """
        Use this method to customize the mapping rule engine.
        Cf. l10n_be_coda_analytic_plan module for an example.
        """
        return []

    @api.model
    def rule_get(self,
                 coda_bank_account_id,
                 trans_type_id=None,
                 trans_family_id=None,
                 trans_code_id=None,
                 trans_category_id=None,
                 struct_comm_type_id=None,
                 partner_id=None,
                 freecomm=None,
                 structcomm=None,
                 payment_reference=None):

        select = \
            'SELECT trans_type_id, trans_family_id, trans_code_id, ' \
            'trans_category_id, ' \
            'struct_comm_type_id, partner_id, freecomm, structcomm, ' \
            'account_id, tax_code_id, analytic_account_id, payment_reference'
        select += self._rule_select_extra(coda_bank_account_id) + ' '
        select += \
            "FROM coda_account_mapping_rule " \
            "WHERE active = TRUE AND coda_bank_account_id = %s " \
            "ORDER BY sequence" % coda_bank_account_id
        self._cr.execute(select)
        rules = self._cr.dictfetchall()
        condition = \
            "(not rule['trans_type_id'] or " \
            "(trans_type_id == rule['trans_type_id'])) and " \
            "(not rule['trans_family_id'] or " \
            "(trans_family_id == rule['trans_family_id'])) " \
            "and (not rule['trans_code_id'] or " \
            "(trans_code_id == rule['trans_code_id'])) and " \
            "(not rule['trans_category_id'] or " \
            "(trans_category_id == rule['trans_category_id'])) " \
            "and (not rule['struct_comm_type_id'] or " \
            "(struct_comm_type_id == rule['struct_comm_type_id'])) and " \
            "(not rule['partner_id'] or " \
            "(partner_id == rule['partner_id'])) " \
            "and (not rule['freecomm'] or (rule['freecomm'].lower() in " \
            "(freecomm and freecomm.lower() or ''))) " \
            "and (not rule['structcomm'] or " \
            "(rule['structcomm'] in (structcomm or ''))) " \
            "and (not rule['payment_reference'] or " \
            "(rule['payment_reference'] in (payment_reference or ''))) "
        result_fields = ['account_id', 'tax_code_id', 'analytic_account_id']
        result_fields += self._rule_result_extra(coda_bank_account_id)
        res = {}
        for rule in rules:
            if eval(condition):
                for f in result_fields:
                    res[f] = rule[f]
                break
        return res
class budget_position(models.Model):
    """Budget Position"""

    _name = 'public_budget.budget_position'
    _description = 'Budget Position'
    _parent_order = 'code'
    _parent_store = True

    _order = "parent_left"

    code = fields.Char(
        string='Code',
        required=True
        )
    name = fields.Char(
        string='Name',
        required=True
        )
    type = fields.Selection(
        [(u'normal', u'Normal'), (u'view', u'View')],
        string='Type',
        required=True,
        default='normal'
        )
    budget_assignment_allowed = fields.Boolean(
        string='Budget Assignment Allowed?'
        )
    category_id = fields.Many2one(
        'public_budget.budget_position_category',
        string='Category'
        )
    inventariable = fields.Boolean(
        string='Inventariable?'
        )
    draft_amount = fields.Float(
        string='Draft Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    preventive_amount = fields.Float(
        string='Preventive Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    definitive_amount = fields.Float(
        string='Definitive Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    to_pay_amount = fields.Float(
        string='To Pay Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    paid_amount = fields.Float(
        string='Paid Amount',
        compute='_get_amounts'
        )
    balance_amount = fields.Float(
        string='Balance Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    projected_amount = fields.Float(
        string='Projected Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    projected_avg = fields.Float(
        string='Projected Avg',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    preventive_avg = fields.Float(
        string='Preventive Perc.',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    amount = fields.Float(
        string='Amount',
        compute='_get_amounts',
        digits=dp.get_precision('Account'),
        )
    parent_left = fields.Integer(
        string='Parent Left',
        select=True
        )
    parent_right = fields.Integer(
        string='Parent Right',
        select=True
        )
    child_ids = fields.One2many(
        'public_budget.budget_position',
        'parent_id',
        string='Childs'
        )
    parent_id = fields.Many2one(
        'public_budget.budget_position',
        string='Parent',
        ondelete='cascade',
        context={'default_type': 'view'},
        domain=[('type', '=', 'view')]
        )
    budget_detail_ids = fields.One2many(
        'public_budget.budget_detail',
        'budget_position_id',
        string='budget_detail_ids'
        )
    budget_modification_detail_ids = fields.One2many(
        'public_budget.budget_modification_detail',
        'budget_position_id',
        string='budget_modification_detail_ids'
        )
    preventive_line_ids = fields.One2many(
        'public_budget.preventive_line',
        'budget_position_id',
        string='Preventive Lines'
        )
    assignment_position_id = fields.Many2one(
        'public_budget.budget_position',
        string='Assignment Position',
        compute='_get_assignment_position',
        store=True,
        )

    @api.one
    # @api.depends(
    #     'preventive_line_ids.affects_budget',
    #     'preventive_line_ids.transaction_id.state',
    #     'preventive_line_ids.preventive_amount',
    #     'preventive_line_ids.definitive_line_ids.amount',
    #     )
    def _get_amounts(self):
        """Update the following fields with the related values to the budget
        and the budget position:
        -draft_amount: amount sum on preventive lines in draft state
        -preventive_amount: amount sum on preventive lines not in draft/cancel
        -definitive_amount: amount sum of definitive lines
        -to_pay_amount: amount sum of lines that has a related voucher in draft
        state
        -paid_amount: amount sum of lines that has a related voucher in open
        state
        -balance_amount: diffference between budget position and preventive
        amount
        """
        if self.type == 'view':
            operator = 'child_of'
        if self.type == 'normal':
            operator = '='

        domain = [
            ('budget_position_id', operator, self.id),
            ('transaction_id.state', 'in', ('open', 'closed')),
            ('affects_budget', '=', True),
            ]

        budget_id = self._context.get('budget_id', False)
        # we add budget_assignment_allowed condition to optimize
        if budget_id and self.budget_assignment_allowed:
            domain.append(('budget_id', '=', budget_id))
            modification_lines = self.env[
                'public_budget.budget_modification_detail'].search([
                    ('budget_modification_id.budget_id', '=', budget_id),
                    ('budget_position_id', operator, self.id)])
            modification_amounts = [line.amount for line in modification_lines]
            initial_lines = self.env['public_budget.budget_detail'].search([
                ('budget_id', '=', budget_id),
                ('budget_position_id', operator, self.id)])
            initial_amounts = [line.initial_amount for line in initial_lines]
            amount = sum(initial_amounts) + sum(modification_amounts)
        else:
            amount = False

        # we exclude lines from preventive lines because constraints sometimes
        # consider the line you are checking and sometimes not, so better we
        # exclude that line and compare to that line amount
        excluded_line_id = self._context.get('excluded_line_id', False)
        if excluded_line_id:
            domain.append(('id', '!=', excluded_line_id))

        draft_preventive_lines = self.env[
            'public_budget.preventive_line'].search(
            domain
            )
        active_preventive_lines = self.env[
            'public_budget.preventive_line'].search(
            domain
            )

        preventive_amount = sum(
            [line.preventive_amount for line in active_preventive_lines])
        self.draft_amount = sum([
            line.preventive_amount
            for line
            in draft_preventive_lines])
        self.preventive_amount = preventive_amount
        self.definitive_amount = sum(
            [line.definitive_amount for line in active_preventive_lines])
        self.to_pay_amount = sum(
            [line.to_pay_amount for line in active_preventive_lines])
        self.paid_amount = sum(
            [line.paid_amount for line in active_preventive_lines])

        day_of_year = datetime.now().timetuple().tm_yday
        projected_amount = preventive_amount / day_of_year * 365
        self.projected_amount = projected_amount

        if self.budget_assignment_allowed:
            projected_avg = amount and \
                projected_amount / amount * 100.0 or 0.0
            self.projected_avg = projected_avg
            self.amount = amount
            preventive_avg = amount and \
                preventive_amount / amount * 100.0 or 0.0
            self.preventive_avg = preventive_avg
            self.balance_amount = self.amount - preventive_amount

    @api.multi
    def name_get(self):
        result = []
        for rec in self:
            result.append(
                (rec.id, "%s - %s" % (rec.code, rec.name)))
        return result

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=100):
        args = args or []
        recs = self.browse()
        if name:
            recs = self.search([('code', operator, name)] + args, limit=limit)
        if not recs:
            recs = self.search([('name', operator, name)] + args, limit=limit)
        return recs.name_get()

    @api.one
    @api.constrains('child_ids', 'type', 'parent_id')
    def _check_type(self):
        if self.child_ids and self.type not in ('view'):
            raise Warning(_('You cannot define children to an account with \
                internal type different of "View".'))

    @api.one
    @api.constrains(
        'budget_modification_detail_ids',
        'budget_detail_ids',
        'child_ids',
        'budget_assignment_allowed',
        'parent_id'
    )
    def _check_budget_assignment_allowed(self):
        # Check before seting budget_assignment_allowed false if position used
        if not self.budget_assignment_allowed and (
                self.budget_modification_detail_ids or self.budget_detail_ids):
            raise Warning(_(
                "You can not set 'Budget Assignment Allowed' to false if\
                budget position is being used in a budget detail or\
                modification."))
        if self.budget_assignment_allowed:
            # Check no parent has budget allowed
            if len(self.get_parent_assignment_position()) >= 1:
                raise Warning(_('In one branch only one budget position can\
                    have Budget Assignment Allowed.'))
            # Check no children has budget allowed
            else:
                children_allowed = self.search([
                    ('id', 'child_of', self.id),
                    ('id', '!=', self.id),
                    ('budget_assignment_allowed', '=', True)])
                if children_allowed:
                    raise Warning(_(
                        'You can not set position %s to Budget Posistion \
                        Allowed as the child position %s has Allowed.') % (
                        self.name, children_allowed[0].name))

    @api.multi
    def get_parent_assignment_position(self):
        self.ensure_one()
        assignment_allowed = self.env['public_budget.budget_position']
        parent = self.parent_id
        while parent:
            if parent.budget_assignment_allowed:
                assignment_allowed += parent
            parent = parent.parent_id
        return assignment_allowed

    @api.one
    @api.depends(
        'parent_id',
        'child_ids',
        'budget_assignment_allowed',
    )
    def _get_assignment_position(self):
        if self.budget_assignment_allowed:
            assignment_position = self
        else:
            assignment_position = self.get_parent_assignment_position()
        self.assignment_position_id = assignment_position.id
class eq_import_helper(models.Model):
    _name = 'eq_import_helper'

    ir_model = fields.Many2one('ir.model')
    old_id = fields.Integer('Old id')
    new_id = fields.Integer('New id')