Ejemplo n.º 1
0
class hr_timesheet_report(osv.osv):
    _name = "hr.timesheet.report"
    _description = "Timesheet"
    _auto = False
    _columns = {
        'year': fields.char('Year',size=64,required=False, readonly=True),
        'day': fields.char('Day', size=128, readonly=True),
        'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
            ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
            ('10','October'), ('11','November'), ('12','December')], 'Month',readonly=True),
        'date': fields.date('Date', readonly=True),
        'name': fields.char('Description', size=64,readonly=True),
        'product_id' : fields.many2one('product.product', 'Product',readonly=True),
        'journal_id' : fields.many2one('account.analytic.journal', 'Journal',readonly=True),
        'general_account_id' : fields.many2one('account.account', 'General Account', readonly=True),
        'user_id': fields.many2one('res.users', 'User',readonly=True),
        'account_id': fields.many2one('account.analytic.account', 'Analytic Account',readonly=True),
        'company_id': fields.many2one('res.company', 'Company',readonly=True),
        'cost': fields.float('Cost',readonly=True, digits_compute=dp.get_precision('Account')),
        'quantity': fields.float('Quantity',readonly=True),
    }

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'hr_timesheet_report')
        cr.execute("""
            create or replace view hr_timesheet_report as (
                select
                    min(t.id) as id,
                    l.date as date,
                    to_char(l.date, 'YYYY-MM-DD') as day,
                    to_char(l.date,'YYYY') as year,
                    to_char(l.date,'MM') as month,
                    sum(l.amount) as cost,
                    sum(l.unit_amount) as quantity,
                    l.account_id as account_id,
                    l.journal_id as journal_id,
                    l.product_id as product_id,
                    l.general_account_id as general_account_id,
                    l.user_id as user_id,
                    l.company_id as company_id,
                    l.currency_id as currency_id
                from
                    hr_analytic_timesheet as t
                    left join account_analytic_line as l ON (t.line_id=l.id)
                group by
                    l.date,
                    l.account_id,
                    l.product_id,
                    l.general_account_id,
                    l.journal_id,
                    l.user_id,
                    l.company_id,
                    l.currency_id
            )
        """)
Ejemplo n.º 2
0
class marketing_campaign(osv.osv):
    _name = "marketing.campaign"
    _description = "Marketing Campaign"

    _columns = {
        'name': fields.char('Name', size=64, required=True),
        'object_id': fields.many2one('ir.model', 'Resource', required=True,
                                      help="Choose the resource on which you want \
this campaign to be run"                        ),
        'partner_field_id': fields.many2one('ir.model.fields', 'Partner Field',
                                            domain="[('model_id', '=', object_id), ('ttype', '=', 'many2one'), ('relation', '=', 'res.partner')]",
                                            help="The generated workitems will be linked to the partner related to the record. "\
                                                  "If the record is the partner itself leave this field empty. "\
                                                  "This is useful for reporting purposes, via the Campaign Analysis or Campaign Follow-up views."),
        'unique_field_id': fields.many2one('ir.model.fields', 'Unique Field',
                                            domain="[('model_id', '=', object_id), ('ttype', 'in', ['char','int','many2one','text','selection'])]",
                                            help='If set, this field will help segments that work in "no duplicates" mode to avoid '\
                                                 'selecting similar records twice. Similar records are records that have the same value for '\
                                                 'this unique field. For example by choosing the "email_from" field for CRM Leads you would prevent '\
                                                 'sending the same campaign to the same email address again. If not set, the "no duplicates" segments '\
                                                 "will only avoid selecting the same record again if it entered the campaign previously. "\
                                                 "Only easily comparable fields like textfields, integers, selections or single relationships may be used."),
        'mode': fields.selection([('test', 'Test Directly'),
                                ('test_realtime', 'Test in Realtime'),
                                ('manual', 'With Manual Confirmation'),
                                ('active', 'Normal')],
                                 'Mode', required=True, help= \
"""Test - It creates and process all the activities directly (without waiting for the delay on transitions) but does not send emails or produce reports.
Test in Realtime - It creates and processes all the activities directly but does not send emails or produce reports.
With Manual Confirmation - the campaigns runs normally, but the user has to validate all workitem manually.
Normal - the campaign runs normally and automatically sends all emails and reports (be very careful with this mode, you're live!)"""),
        'state': fields.selection([('draft', 'New'),
                                   ('running', 'Running'),
                                   ('cancelled', 'Cancelled'),
                                   ('done', 'Done')],
                                   'Status',),
        'activity_ids': fields.one2many('marketing.campaign.activity',
                                       'campaign_id', 'Activities'),
        'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for running this campaign. You may also specify variable cost and revenue on each campaign activity. Cost and Revenue statistics are included in Campaign Reporting.", digits_compute=dp.get_precision('Purchase Price')),
    }

    _defaults = {
        'state': lambda *a: 'draft',
        'mode': lambda *a: 'test',
    }

    def state_running_set(self, cr, uid, ids, *args):
        # TODO check that all subcampaigns are running
        campaign = self.browse(cr, uid, ids[0])

        if not campaign.activity_ids:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be started: there are no activities in it."
                  ))

        has_start = False
        has_signal_without_from = False

        for activity in campaign.activity_ids:
            if activity.start:
                has_start = True
            if activity.signal and len(activity.from_ids) == 0:
                has_signal_without_from = True

        if not has_start and not has_signal_without_from:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be started: it doesn't have any starting activity. Modify campaign's activities to mark one as the starting point."
                  ))

        return self.write(cr, uid, ids, {'state': 'running'})

    def state_done_set(self, cr, uid, ids, *args):
        # TODO check that this campaign is not a subcampaign in running mode.
        segment_ids = self.pool.get('marketing.campaign.segment').search(
            cr, uid, [('campaign_id', 'in', ids), ('state', '=', 'running')])
        if segment_ids:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be marked as done before all segments are closed."
                  ))
        self.write(cr, uid, ids, {'state': 'done'})
        return True

    def state_cancel_set(self, cr, uid, ids, *args):
        # TODO check that this campaign is not a subcampaign in running mode.
        self.write(cr, uid, ids, {'state': 'cancelled'})
        return True

    # dead code
    def signal(self,
               cr,
               uid,
               model,
               res_id,
               signal,
               run_existing=True,
               context=None):
        record = self.pool.get(model).browse(cr, uid, res_id, context)
        return self._signal(cr, uid, record, signal, run_existing, context)

    #dead code
    def _signal(self,
                cr,
                uid,
                record,
                signal,
                run_existing=True,
                context=None):
        if not signal:
            raise ValueError('signal cannot be False')

        Workitems = self.pool.get('marketing.campaign.workitem')
        domain = [('object_id.model', '=', record._table._name),
                  ('state', '=', 'running')]
        campaign_ids = self.search(cr, uid, domain, context=context)
        for campaign in self.browse(cr, uid, campaign_ids, context=context):
            for activity in campaign.activity_ids:
                if activity.signal != signal:
                    continue

                data = dict(activity_id=activity.id,
                            res_id=record.id,
                            state='todo')
                wi_domain = [(k, '=', v) for k, v in data.items()]

                wi_ids = Workitems.search(cr, uid, wi_domain, context=context)
                if wi_ids:
                    if not run_existing:
                        continue
                else:
                    partner = self._get_partner_for(campaign, record)
                    if partner:
                        data['partner_id'] = partner.id
                    wi_id = Workitems.create(cr, uid, data, context=context)
                    wi_ids = [wi_id]
                Workitems.process(cr, uid, wi_ids, context=context)
        return True

    def _get_partner_for(self, campaign, record):
        partner_field = campaign.partner_field_id.name
        if partner_field:
            return getattr(record, partner_field)
        elif campaign.object_id.model == 'res.partner':
            return record
        return None

    # prevent duplication until the server properly duplicates several levels of nested o2m
    def copy(self, cr, uid, id, default=None, context=None):
        raise osv.except_osv(
            _("Operation not supported"),
            _("You can not duplicate a campaign, it's not supported yet."))

    def _find_duplicate_workitems(self,
                                  cr,
                                  uid,
                                  record,
                                  campaign_rec,
                                  context=None):
        """Finds possible duplicates workitems for a record in this campaign, based on a uniqueness
           field.

           :param record: browse_record to find duplicates workitems for.
           :param campaign_rec: browse_record of campaign
        """
        Workitems = self.pool.get('marketing.campaign.workitem')
        duplicate_workitem_domain = [('res_id', '=', record.id),
                                     ('campaign_id', '=', campaign_rec.id)]
        unique_field = campaign_rec.unique_field_id
        if unique_field:
            unique_value = getattr(record, unique_field.name, None)
            if unique_value:
                if unique_field.ttype == 'many2one':
                    unique_value = unique_value.id
                similar_res_ids = self.pool.get(
                    campaign_rec.object_id.model).search(
                        cr,
                        uid, [(unique_field.name, '=', unique_value)],
                        context=context)
                if similar_res_ids:
                    duplicate_workitem_domain = [
                        ('res_id', 'in', similar_res_ids),
                        ('campaign_id', '=', campaign_rec.id)
                    ]
        return Workitems.search(cr,
                                uid,
                                duplicate_workitem_domain,
                                context=context)
Ejemplo n.º 3
0
class marketing_campaign_activity(osv.osv):
    _name = "marketing.campaign.activity"
    _order = "name"
    _description = "Campaign Activity"

    _action_types = [
        ('email', 'Email'),
        ('report', 'Report'),
        ('action', 'Custom Action'),
        # TODO implement the subcampaigns.
        # TODO implement the subcampaign out. disallow out transitions from
        # subcampaign activities ?
        #('subcampaign', 'Sub-Campaign'),
    ]

    _columns = {
        'name':
        fields.char('Name', size=128, required=True),
        'campaign_id':
        fields.many2one('marketing.campaign',
                        'Campaign',
                        required=True,
                        ondelete='cascade',
                        select=1),
        'object_id':
        fields.related('campaign_id',
                       'object_id',
                       type='many2one',
                       relation='ir.model',
                       string='Object',
                       readonly=True),
        'start':
        fields.boolean(
            'Start',
            help="This activity is launched when the campaign starts.",
            select=True),
        'condition':
        fields.text(
            'Condition',
            size=256,
            required=True,
            help=
            "Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled."
            "The expression may use the following [browsable] variables:\n"
            "   - activity: the campaign activity\n"
            "   - workitem: the campaign workitem\n"
            "   - resource: the resource object this campaign item represents\n"
            "   - transitions: list of campaign transitions outgoing from this activity\n"
            "...- re: Python regular expression module"),
        'type':
        fields.selection(
            _action_types,
            'Type',
            required=True,
            help=
            """The type of action to execute when an item enters this activity, such as:
   - Email: send an email using a predefined email template
   - Report: print an existing Report defined on the resource item and save it into a specific directory
   - Custom Action: execute a predefined action, e.g. to modify the fields of the resource record
  """),
        'email_template_id':
        fields.many2one(
            'email.template',
            "Email Template",
            help='The email to send when this activity is activated'),
        'report_id':
        fields.many2one(
            'ir.actions.report.xml',
            "Report",
            help='The report to generate when this activity is activated',
        ),
        'report_directory_id':
        fields.many2one(
            'document.directory',
            'Directory',
            help="This folder is used to store the generated reports"),
        'server_action_id':
        fields.many2one(
            'ir.actions.server',
            string='Action',
            help="The action to perform when this activity is activated"),
        'to_ids':
        fields.one2many('marketing.campaign.transition', 'activity_from_id',
                        'Next Activities'),
        'from_ids':
        fields.one2many('marketing.campaign.transition', 'activity_to_id',
                        'Previous Activities'),
        'variable_cost':
        fields.float(
            'Variable Cost',
            help=
            "Set a variable cost if you consider that every campaign item that has reached this point has entailed a certain cost. You can get cost statistics in the Reporting section",
            digits_compute=dp.get_precision('Purchase Price')),
        'revenue':
        fields.float(
            'Revenue',
            help=
            "Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section",
            digits_compute=dp.get_precision('Sale Price')),
        'signal':
        fields.char(
            'Signal',
            size=128,
            help=
            'An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent'
        ),
        'keep_if_condition_not_met':
        fields.boolean(
            "Don't Delete Workitems",
            help=
            "By activating this option, workitems that aren't executed because the condition is not met are marked as cancelled instead of being deleted."
        )
    }

    _defaults = {
        'type': lambda *a: 'email',
        'condition': lambda *a: 'True',
    }

    def search(self,
               cr,
               uid,
               args,
               offset=0,
               limit=None,
               order=None,
               context=None,
               count=False):
        if context == None:
            context = {}
        if 'segment_id' in context and context['segment_id']:
            segment_obj = self.pool.get('marketing.campaign.segment').browse(
                cr, uid, context['segment_id'])
            act_ids = []
            for activity in segment_obj.campaign_id.activity_ids:
                act_ids.append(activity.id)
            return act_ids
        return super(marketing_campaign_activity,
                     self).search(cr, uid, args, offset, limit, order, context,
                                  count)

    #dead code
    def _process_wi_report(self, cr, uid, activity, workitem, context=None):
        service = netsvc.LocalService('report.%s' %
                                      activity.report_id.report_name)
        (report_data, format) = service.create(cr, uid, [], {}, {})
        attach_vals = {
            'name':
            '%s_%s_%s' % (activity.report_id.report_name, activity.name,
                          workitem.partner_id.name),
            'datas_fname':
            '%s.%s' %
            (activity.report_id.report_name, activity.report_id.report_type),
            'parent_id':
            activity.report_directory_id.id,
            'datas':
            base64.encodestring(report_data),
            'file_type':
            format
        }
        self.pool.get('ir.attachment').create(cr, uid, attach_vals)
        return True

    def _process_wi_email(self, cr, uid, activity, workitem, context=None):
        return self.pool.get('email.template').send_mail(
            cr,
            uid,
            activity.email_template_id.id,
            workitem.res_id,
            context=context)

    #dead code
    def _process_wi_action(self, cr, uid, activity, workitem, context=None):
        if context is None:
            context = {}
        server_obj = self.pool.get('ir.actions.server')

        action_context = dict(context,
                              active_id=workitem.res_id,
                              active_ids=[workitem.res_id],
                              active_model=workitem.object_id.model,
                              workitem=workitem)
        res = server_obj.run(cr,
                             uid, [activity.server_action_id.id],
                             context=action_context)
        # server action return False if the action is performed
        # except client_action, other and python code
        return res == False and True or res

    def process(self, cr, uid, act_id, wi_id, context=None):
        activity = self.browse(cr, uid, act_id, context=context)
        method = '_process_wi_%s' % (activity.type, )
        action = getattr(self, method, None)
        if not action:
            raise NotImplementedError(
                'method %r in not implemented on %r object' % (method, self))

        workitem_obj = self.pool.get('marketing.campaign.workitem')
        workitem = workitem_obj.browse(cr, uid, wi_id, context=context)
        return action(cr, uid, activity, workitem, context=context)
Ejemplo n.º 4
0
class report_stock_move(osv.osv):
    _name = "report.stock.move"
    _description = "Moves Statistics"
    _auto = False
    _columns = {
        'date':
        fields.date('Date', readonly=True),
        'year':
        fields.char('Year', size=4, readonly=True),
        'day':
        fields.char('Day', size=128, readonly=True),
        'month':
        fields.selection([('01', 'January'), ('02', 'February'),
                          ('03', 'March'), ('04', 'April'), ('05', 'May'),
                          ('06', 'June'), ('07', 'July'), ('08', 'August'),
                          ('09', 'September'), ('10', 'October'),
                          ('11', 'November'), ('12', 'December')],
                         'Month',
                         readonly=True),
        'partner_id':
        fields.many2one('res.partner.address', 'Partner', readonly=True),
        'product_id':
        fields.many2one('product.product', 'Product', readonly=True),
        'company_id':
        fields.many2one('res.company', 'Company', readonly=True),
        'picking_id':
        fields.many2one('stock.picking', 'Packing', readonly=True),
        'type':
        fields.selection(
            [('out', 'Sending Goods'), ('in', 'Getting Goods'),
             ('internal', 'Internal'), ('other', 'Others')],
            'Shipping Type',
            required=True,
            select=True,
            help="Shipping type specify, goods coming in or going out."),
        'location_id':
        fields.many2one(
            'stock.location',
            'Source Location',
            readonly=True,
            select=True,
            help=
            "Sets a location if you produce at a fixed location. This can be a partner location if you subcontract the manufacturing operations."
        ),
        'location_dest_id':
        fields.many2one(
            'stock.location',
            'Dest. Location',
            readonly=True,
            select=True,
            help="Location where the system will stock the finished products."
        ),
        'state':
        fields.selection([('draft', 'Draft'), ('waiting', 'Waiting'),
                          ('confirmed', 'Confirmed'),
                          ('assigned', 'Available'), ('done', 'Done'),
                          ('cancel', 'Cancelled')],
                         'State',
                         readonly=True,
                         select=True),
        'product_qty':
        fields.integer('Quantity', readonly=True),
        'categ_id':
        fields.many2one(
            'product.category',
            'Product Category',
        ),
        'product_qty_in':
        fields.integer('In Qty', readonly=True),
        'product_qty_out':
        fields.integer('Out Qty', readonly=True),
        'value':
        fields.float('Total Value', required=True),
        'day_diff2':
        fields.float('Lag (Days)',
                     readonly=True,
                     digits_compute=dp.get_precision('Shipping Delay'),
                     group_operator="avg"),
        'day_diff1':
        fields.float('Planned Lead Time (Days)',
                     readonly=True,
                     digits_compute=dp.get_precision('Shipping Delay'),
                     group_operator="avg"),
        'day_diff':
        fields.float('Execution Lead Time (Days)',
                     readonly=True,
                     digits_compute=dp.get_precision('Shipping Delay'),
                     group_operator="avg"),
        'stock_journal':
        fields.many2one('stock.journal', 'Stock Journal', select=True),
    }

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_stock_move')
        cr.execute("""
            CREATE OR REPLACE view report_stock_move AS (
                SELECT
                        min(sm_id) as id,
                        date_trunc('day',al.dp) as date,
                        al.curr_year as year,
                        al.curr_month as month,
                        al.curr_day as day,
                        al.curr_day_diff as day_diff,
                        al.curr_day_diff1 as day_diff1,
                        al.curr_day_diff2 as day_diff2,
                        al.location_id as location_id,
                        al.picking_id as picking_id,
                        al.company_id as company_id,
                        al.location_dest_id as location_dest_id,
                        al.product_qty,
                        al.out_qty as product_qty_out,
                        al.in_qty as product_qty_in,
                        al.address_id as partner_id,
                        al.product_id as product_id,
                        al.state as state ,
                        al.product_uom as product_uom,
                        al.categ_id as categ_id,
                        coalesce(al.type, 'other') as type,
                        al.stock_journal as stock_journal,
                        sum(al.in_value - al.out_value) as value
                    FROM (SELECT
                        CASE WHEN sp.type in ('out') THEN
                            sum(sm.product_qty * pu.factor)
                            ELSE 0.0
                            END AS out_qty,
                        CASE WHEN sp.type in ('in') THEN
                            sum(sm.product_qty * pu.factor)
                            ELSE 0.0
                            END AS in_qty,
                        CASE WHEN sp.type in ('out') THEN
                            sum(sm.product_qty * pu.factor) * pt.standard_price
                            ELSE 0.0
                            END AS out_value,
                        CASE WHEN sp.type in ('in') THEN
                            sum(sm.product_qty * pu.factor) * pt.standard_price
                            ELSE 0.0
                            END AS in_value,
                        min(sm.id) as sm_id,
                        sm.date as dp,
                        to_char(date_trunc('day',sm.date), 'YYYY') as curr_year,
                        to_char(date_trunc('day',sm.date), 'MM') as curr_month,
                        to_char(date_trunc('day',sm.date), 'YYYY-MM-DD') as curr_day,
                        avg(date(sm.date)-date(sm.create_date)) as curr_day_diff,
                        avg(date(sm.date_expected)-date(sm.create_date)) as curr_day_diff1,
                        avg(date(sm.date)-date(sm.date_expected)) as curr_day_diff2,
                        sm.location_id as location_id,
                        sm.location_dest_id as location_dest_id,
                        sum(sm.product_qty) as product_qty,
                        pt.categ_id as categ_id ,
                        sm.address_id as address_id,
                        sm.product_id as product_id,
                        sm.picking_id as picking_id,
                            sm.company_id as company_id,
                            sm.state as state,
                            sm.product_uom as product_uom,
                            sp.type as type,
                            sp.stock_journal_id AS stock_journal
                    FROM
                        stock_move sm
                        LEFT JOIN stock_picking sp ON (sm.picking_id=sp.id)
                        LEFT JOIN product_product pp ON (sm.product_id=pp.id)
                        LEFT JOIN product_uom pu ON (sm.product_uom=pu.id)
                        LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
                        LEFT JOIN stock_location sl ON (sm.location_id = sl.id)

                    GROUP BY
                        sm.id,sp.type, sm.date,sm.address_id,
                        sm.product_id,sm.state,sm.product_uom,sm.date_expected,
                        sm.product_id,pt.standard_price, sm.picking_id, sm.product_qty,
                        sm.company_id,sm.product_qty, sm.location_id,sm.location_dest_id,pu.factor,pt.categ_id, sp.stock_journal_id)
                    AS al

                    GROUP BY
                        al.out_qty,al.in_qty,al.curr_year,al.curr_month,
                        al.curr_day,al.curr_day_diff,al.curr_day_diff1,al.curr_day_diff2,al.dp,al.location_id,al.location_dest_id,
                        al.address_id,al.product_id,al.state,al.product_uom,
                        al.picking_id,al.company_id,al.type,al.product_qty, al.categ_id, al.stock_journal
               )
        """)
Ejemplo n.º 5
0
class report_stock_inventory(osv.osv):
    _name = "report.stock.inventory"
    _description = "Stock Statistics"
    _auto = False
    _columns = {
        'date':
        fields.datetime('Date', readonly=True),
        'partner_id':
        fields.many2one('res.partner.address', 'Partner', readonly=True),
        'product_id':
        fields.many2one('product.product', 'Product', readonly=True),
        'product_categ_id':
        fields.many2one('product.category', 'Product Category', readonly=True),
        'location_id':
        fields.many2one('stock.location', 'Location', readonly=True),
        'prodlot_id':
        fields.many2one('stock.production.lot', 'Lot', readonly=True),
        'company_id':
        fields.many2one('res.company', 'Company', readonly=True),
        'product_qty':
        fields.float('Quantity',
                     digits_compute=dp.get_precision('Product UoM'),
                     readonly=True),
        'value':
        fields.float('Total Value',
                     digits_compute=dp.get_precision('Account'),
                     required=True),
        'state':
        fields.selection(
            [('draft', 'Draft'), ('waiting', 'Waiting'),
             ('confirmed', 'Confirmed'), ('assigned', 'Available'),
             ('done', 'Done'), ('cancel', 'Cancelled')],
            'State',
            readonly=True,
            select=True,
            help=
            'When the stock move is created it is in the \'Draft\' state.\n After that it is set to \'Confirmed\' state.\n If stock is available state is set to \'Avaiable\'.\n When the picking it done the state is \'Done\'.\
              \nThe state is \'Waiting\' if the move is waiting for another one.'
        ),
        'location_type':
        fields.selection(
            [('supplier', 'Supplier Location'), ('view', 'View'),
             ('internal', 'Internal Location'),
             ('customer', 'Customer Location'), ('inventory', 'Inventory'),
             ('procurement', 'Procurement'), ('production', 'Production'),
             ('transit', 'Transit Location for Inter-Companies Transfers')],
            'Location Type',
            required=True),
    }

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_stock_inventory')
        cr.execute("""
CREATE OR REPLACE view report_stock_inventory AS (
    (SELECT
        min(m.id) as id, m.date as date,
        m.address_id as partner_id, m.location_id as location_id,
        m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type,
        m.company_id,
        m.state as state, m.prodlot_id as prodlot_id,
        coalesce(sum(-pt.standard_price * m.product_qty * pu.factor / u.factor)::decimal, 0.0) as value,
        CASE when pt.uom_id = m.product_uom
        THEN
        coalesce(sum(-m.product_qty)::decimal, 0.0)
        ELSE
        coalesce(sum(-m.product_qty * pu.factor / u.factor )::decimal, 0.0) END as product_qty
    FROM
        stock_move m
            LEFT JOIN stock_picking p ON (m.picking_id=p.id)
            LEFT JOIN product_product pp ON (m.product_id=pp.id)
                LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
                LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
            LEFT JOIN product_uom u ON (m.product_uom=u.id)
            LEFT JOIN stock_location l ON (m.location_id=l.id)
    GROUP BY
        m.id, m.product_id, m.product_uom, pt.categ_id, m.address_id, m.location_id,  m.location_dest_id,
        m.prodlot_id, m.date, m.state, l.usage, m.company_id,pt.uom_id
) UNION ALL (
    SELECT
        -m.id as id, m.date as date,
        m.address_id as partner_id, m.location_dest_id as location_id,
        m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type,
        m.company_id,
        m.state as state, m.prodlot_id as prodlot_id,
        coalesce(sum(pt.standard_price * m.product_qty * pu.factor / u.factor )::decimal, 0.0) as value,
        CASE when pt.uom_id = m.product_uom
        THEN
        coalesce(sum(m.product_qty)::decimal, 0.0)
        ELSE
        coalesce(sum(m.product_qty * pu.factor / u.factor)::decimal, 0.0) END as product_qty
    FROM
        stock_move m
            LEFT JOIN stock_picking p ON (m.picking_id=p.id)
            LEFT JOIN product_product pp ON (m.product_id=pp.id)
                LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
                LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
            LEFT JOIN product_uom u ON (m.product_uom=u.id)
            LEFT JOIN stock_location l ON (m.location_dest_id=l.id)
    GROUP BY
        m.id, m.product_id, m.product_uom, pt.categ_id, m.address_id, m.location_id, m.location_dest_id,
        m.prodlot_id, m.date, m.state, l.usage, m.company_id,pt.uom_id
    )
);
        """)
Ejemplo n.º 6
0
class report_account_analytic_line_to_invoice(osv.osv):
    _name = "report.account.analytic.line.to.invoice"
    _description = "Analytic lines to invoice report"
    _auto = False
    _columns = {
        'name':
        fields.char('Year', size=64, required=False, readonly=True),
        'product_id':
        fields.many2one('product.product', 'Product', readonly=True),
        'account_id':
        fields.many2one('account.analytic.account',
                        'Analytic account',
                        readonly=True),
        'product_uom_id':
        fields.many2one('product.uom', 'UoM', readonly=True),
        'unit_amount':
        fields.float('Units', readonly=True),
        'sale_price':
        fields.float('Sale price',
                     readonly=True,
                     digits_compute=dp.get_precision('Sale Price')),
        'amount':
        fields.float('Amount',
                     readonly=True,
                     digits_compute=dp.get_precision('Account')),
        'month':
        fields.selection([('01', 'January'), ('02', 'February'),
                          ('03', 'March'), ('04', 'April'), ('05', 'May'),
                          ('06', 'June'), ('07', 'July'), ('08', 'August'),
                          ('09', 'September'), ('10', 'October'),
                          ('11', 'November'), ('12', 'December')],
                         'Month',
                         readonly=True),
    }
    _order = 'name desc, product_id asc, account_id asc'

    def init(self, cr):
        tools.drop_view_if_exists(cr,
                                  'report_account_analytic_line_to_invoice')
        cr.execute("""
            CREATE OR REPLACE VIEW report_account_analytic_line_to_invoice AS (
                SELECT
                    DISTINCT(to_char(l.date,'MM')) as month,
                    to_char(l.date, 'YYYY') as name,
                    MIN(l.id) AS id,
                    l.product_id,
                    l.account_id,
                    SUM(l.amount) AS amount,
                    SUM(l.unit_amount*t.list_price) AS sale_price,
                    SUM(l.unit_amount) AS unit_amount,
                    l.product_uom_id
                FROM
                    account_analytic_line l
                left join
                    product_product p on (l.product_id=p.id)
                left join
                    product_template t on (p.product_tmpl_id=t.id)
                WHERE
                    (invoice_id IS NULL) and (to_invoice IS NOT NULL)
                GROUP BY
                    to_char(l.date, 'YYYY'), to_char(l.date,'MM'), product_id, product_uom_id, account_id
            )
        """)
class partner_event_registration(osv.osv_memory):
    """  event Registration """

    _name = "partner.event.registration"
    _description = __doc__
    _order = 'event_id'

    _columns = {
        'event_id':
        fields.many2one('event.event', 'Event'),
        'event_type':
        fields.many2one('event.type', 'Type', readonly=True),
        'unit_price':
        fields.float('Registration Cost',
                     digits_compute=dp.get_precision('Sale Price')),
        'start_date':
        fields.datetime('Start date',
                        help="Beginning Date of Event",
                        readonly=True),
        'end_date':
        fields.datetime('Closing date',
                        help="Closing Date of Event",
                        readonly=True),
        'nb_register':
        fields.integer('Number of Registration'),
    }
    _defaults = {
        'nb_register': 1,
    }

    def open_registration(self, cr, uid, ids, context=None):
        """This Function Open Registration For Given Event id and Partner.

        """
        value = {}
        res_obj = self.pool.get('res.partner')
        addr_obj = self.pool.get('res.partner.address')
        reg_obj = self.pool.get('event.registration')
        mod_obj = self.pool.get('ir.model.data')

        record_ids = context and context.get('active_ids', []) or []
        addr = res_obj.address_get(cr, uid, record_ids)
        email = False
        contact_id = addr.get('default', False)
        if contact_id:
            email = addr_obj.browse(cr, uid, contact_id, context=context).email

        result = mod_obj.get_object_reference(cr, uid, 'event',
                                              'view_registration_search')
        res = result and result[1] or False

        # Select the view

        id2 = mod_obj.get_object_reference(cr, uid, 'event',
                                           'view_event_registration_form')
        id2 = id2 and id2[1] or False
        id3 = mod_obj.get_object_reference(cr, uid, 'event',
                                           'view_event_registration_tree')
        id3 = id3 and id3[1] or False

        for current in self.browse(cr, uid, ids, context=context):
            for partner in res_obj.browse(cr, uid, record_ids,
                                          context=context):
                new_case = reg_obj.create(
                    cr,
                    uid, {
                        'name': 'Registration',
                        'event_id': current.event_id and current.event_id.id
                        or False,
                        'unit_price': current.unit_price,
                        'partner_id': partner.id,
                        'partner_invoice_id': partner.id,
                        'event_product': current.event_id.product_id.name,
                        'contact_id': contact_id,
                        'email_from': email,
                        'nb_register': current.nb_register,
                    },
                    context=context)

        value = {
            'name':
            _('Event Registration'),
            'view_type':
            'form',
            'view_mode':
            'tree,form',
            'res_model':
            'event.registration',
            'res_id':
            new_case,
            'views': [(id2, 'form'), (id3, 'tree'), (False, 'calendar'),
                      (False, 'graph')],
            'type':
            'ir.actions.act_window',
            'search_view_id':
            res
        }
        return value

    def name_get(self, cr, uid, ids, context=None):
        """Overrides orm name_get method
        @param ids: List of partner_event_register ids
        """

        res = []
        if not ids:
            return res
        reads = self.read(cr,
                          uid,
                          ids, ['event_type', 'event_id'],
                          context=context)
        for record in reads:
            event_id = record['event_id'][1]
            if record['event_type']:
                event_id = record['event_type'][1] + ' on ' + event_id
            res.append((record['id'], event_id))
        return res

    def onchange_event_id(self, cr, uid, ids, event_id, context=None):
        res = {}
        event_obj = self.pool.get('event.event')
        product_obj = self.pool.get('product.product')
        partner_obj = self.pool.get('res.partner')
        if context is None:
            context = {}
        partner_id = context.get('active_id', False)
        if event_id:
            event = event_obj.browse(cr, uid, event_id, context=context)
            pricelist_id = event.pricelist_id and event.pricelist_id.id or False
            if partner_id:
                partner = partner_obj.browse(cr,
                                             uid,
                                             partner_id,
                                             context=context)
                pricelist_id = pricelist_id or partner.property_product_pricelist.id
            unit_price = product_obj._product_price(
                cr, uid, [event.product_id.id], False, False,
                {'pricelist': pricelist_id})[event.product_id.id]

            res['value'] = {
                'event_type': event.type and event.type.id or False,
                'start_date': event.date_begin,
                'end_date': event.date_end,
                'unit_price': unit_price,
            }
        return res
Ejemplo n.º 8
0
class account_analytic_account(osv.osv):
    _name = "account.analytic.account"
    _inherit = "account.analytic.account"

    def _analysis_all(self, cr, uid, ids, fields, arg, context=None):
        dp = 2
        res = dict([(i, {}) for i in ids])
        parent_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        accounts = self.browse(cr, uid, ids, context=context)

        for f in fields:
            if f == 'user_ids':
                cr.execute('SELECT MAX(id) FROM res_users')
                max_user = cr.fetchone()[0]
                if parent_ids:
                    cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user ' \
                               'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
                    result = cr.fetchall()
                else:
                    result = []
                for id in ids:
                    res[id][f] = [int((id * max_user) + x[0]) for x in result]
            elif f == 'month_ids':
                if parent_ids:
                    cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month ' \
                               'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
                    result = cr.fetchall()
                else:
                    result = []
                for id in ids:
                    res[id][f] = [
                        int(id * 1000000 + int(x[0])) for x in result
                    ]
            elif f == 'last_worked_invoiced_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, MAX(date) \
                            FROM account_analytic_line \
                            WHERE account_id IN %s \
                                AND invoice_id IS NOT NULL \
                            GROUP BY account_analytic_line.account_id;",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = sum
            elif f == 'ca_to_invoice':
                for id in ids:
                    res[id][f] = 0.0
                res2 = {}
                if parent_ids:
                    # Amount uninvoiced hours to invoice at sale price
                    # Warning
                    # This computation doesn't take care of pricelist !
                    # Just consider list_price
                    cr.execute(
                        """SELECT account_analytic_account.id, \
                                COALESCE(SUM (product_template.list_price * \
                                    account_analytic_line.unit_amount * \
                                    ((100-hr_timesheet_invoice_factor.factor)/100)), 0.0) \
                                    AS ca_to_invoice \
                            FROM product_template \
                            JOIN product_product \
                                ON product_template.id = product_product.product_tmpl_id \
                            JOIN account_analytic_line \
                                ON account_analytic_line.product_id = product_product.id \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            JOIN account_analytic_account \
                                ON account_analytic_account.id = account_analytic_line.account_id \
                            JOIN hr_timesheet_invoice_factor \
                                ON hr_timesheet_invoice_factor.id = account_analytic_account.to_invoice \
                            WHERE account_analytic_account.id IN %s \
                                AND account_analytic_line.invoice_id IS NULL \
                                AND account_analytic_line.to_invoice IS NOT NULL \
                                AND account_analytic_journal.type IN ('purchase','general') \
                            GROUP BY account_analytic_account.id;""",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(sum, dp)

                # sum both result on account_id
                for id in ids:
                    res[id][f] = round(res.get(id, {}).get(f, 0.0),
                                       dp) + round(res2.get(id, 0.0), 2)
            elif f == 'last_invoice_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, \
                                DATE(MAX(account_invoice.date_invoice)) \
                            FROM account_analytic_line \
                            JOIN account_invoice \
                                ON account_analytic_line.invoice_id = account_invoice.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_line.invoice_id IS NOT NULL \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    for account_id, lid in cr.fetchall():
                        res[account_id][f] = lid
            elif f == 'last_worked_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, MAX(date) \
                            FROM account_analytic_line \
                            WHERE account_id IN %s \
                                AND invoice_id IS NULL \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    for account_id, lwd in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = lwd
            elif f == 'hours_qtt_non_invoiced':
                for id in ids:
                    res[id][f] = 0.0
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
                            FROM account_analytic_line \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_journal.type='general' \
                                AND invoice_id IS NULL \
                                AND to_invoice IS NOT NULL \
                            GROUP BY account_analytic_line.account_id;",
                        (parent_ids, ))
                    for account_id, sua in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(sua, dp)
                for id in ids:
                    res[id][f] = round(res[id][f], dp)
            elif f == 'hours_quantity':
                for id in ids:
                    res[id][f] = 0.0
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
                            FROM account_analytic_line \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_journal.type='general' \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    ff = cr.fetchall()
                    for account_id, hq in ff:
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(hq, dp)
                for id in ids:
                    res[id][f] = round(res[id][f], dp)
            elif f == 'ca_theorical':
                # TODO Take care of pricelist and purchase !
                for id in ids:
                    res[id][f] = 0.0
                # Warning
                # This computation doesn't take care of pricelist !
                # Just consider list_price
                if parent_ids:
                    cr.execute(
                        """SELECT account_analytic_line.account_id AS account_id, \
                                COALESCE(SUM((account_analytic_line.unit_amount * pt.list_price) \
                                    - (account_analytic_line.unit_amount * pt.list_price \
                                        * hr.factor)), 0.0) AS somme
                            FROM account_analytic_line \
                            LEFT JOIN account_analytic_journal \
                                ON (account_analytic_line.journal_id = account_analytic_journal.id) \
                            JOIN product_product pp \
                                ON (account_analytic_line.product_id = pp.id) \
                            JOIN product_template pt \
                                ON (pp.product_tmpl_id = pt.id) \
                            JOIN account_analytic_account a \
                                ON (a.id=account_analytic_line.account_id) \
                            JOIN hr_timesheet_invoice_factor hr \
                                ON (hr.id=a.to_invoice) \
                        WHERE account_analytic_line.account_id IN %s \
                            AND a.to_invoice IS NOT NULL \
                            AND account_analytic_journal.type IN ('purchase', 'general')
                        GROUP BY account_analytic_line.account_id""",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        res[account_id][f] = round(sum, dp)
        return res

    def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        res_final = {}
        child_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        for i in child_ids:
            res[i] = 0.0
        if not child_ids:
            return res

        if child_ids:
            cr.execute(
                "SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) \
                    FROM account_analytic_line \
                    JOIN account_analytic_journal \
                        ON account_analytic_line.journal_id = account_analytic_journal.id  \
                    WHERE account_analytic_line.account_id IN %s \
                        AND account_analytic_journal.type = 'sale' \
                    GROUP BY account_analytic_line.account_id", (child_ids, ))
            for account_id, sum in cr.fetchall():
                res[account_id] = round(sum, 2)
        res_final = res
        return res_final

    def _total_cost_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        res_final = {}
        child_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        for i in child_ids:
            res[i] = 0.0
        if not child_ids:
            return res
        if child_ids:
            cr.execute(
                """SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) \
                    FROM account_analytic_line \
                    JOIN account_analytic_journal \
                        ON account_analytic_line.journal_id = account_analytic_journal.id \
                    WHERE account_analytic_line.account_id IN %s \
                        AND amount<0 \
                    GROUP BY account_analytic_line.account_id""",
                (child_ids, ))
            for account_id, sum in cr.fetchall():
                res[account_id] = round(sum, 2)
        res_final = res
        return res_final

    def _remaining_hours_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.quantity_max != 0:
                res[account.id] = account.quantity_max - account.hours_quantity
            else:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.
                id] = account.hours_quantity - account.hours_qtt_non_invoiced
            if res[account.id] < 0:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _revenue_per_hour_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.hours_qtt_invoiced == 0:
                res[account.id] = 0.0
            else:
                res[account.
                    id] = account.ca_invoiced / account.hours_qtt_invoiced
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _real_margin_rate_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.ca_invoiced == 0:
                res[account.id] = 0.0
            elif account.total_cost != 0.0:
                res[account.
                    id] = -(account.real_margin / account.total_cost) * 100
            else:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _remaining_ca_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.amount_max != 0:
                res[account.id] = account.amount_max - account.ca_invoiced
            else:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _real_margin_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = account.ca_invoiced + account.total_cost
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _theorical_margin_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = account.ca_theorical + account.total_cost
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _is_overdue_quantity(self,
                             cr,
                             uid,
                             ids,
                             fieldnames,
                             args,
                             context=None):
        result = dict.fromkeys(ids, 0)
        for record in self.browse(cr, uid, ids, context=context):
            if record.quantity_max > 0.0:
                result[record.id] = int(
                    record.hours_quantity >= record.quantity_max)
            else:
                result[record.id] = 0
        return result

    def _get_analytic_account(self, cr, uid, ids, context=None):
        result = set()
        for line in self.pool.get('account.analytic.line').browse(
                cr, uid, ids, context=context):
            result.add(line.account_id.id)
        return list(result)

    _columns = {
        'is_overdue_quantity':
        fields.function(_is_overdue_quantity,
                        method=True,
                        type='boolean',
                        string='Overdue Quantity',
                        store={
                            'account.analytic.line':
                            (_get_analytic_account, None, 20),
                        }),
        'ca_invoiced':
        fields.function(
            _ca_invoiced_calc,
            type='float',
            string='Invoiced Amount',
            help="Total customer invoiced amount for this account.",
            digits_compute=dp.get_precision('Account')),
        'total_cost':
        fields.function(
            _total_cost_calc,
            type='float',
            string='Total Costs',
            help=
            "Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets.",
            digits_compute=dp.get_precision('Account')),
        'ca_to_invoice':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Uninvoiced Amount',
            help=
            "If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs.",
            digits_compute=dp.get_precision('Account')),
        'ca_theorical':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Theoretical Revenue',
            help=
            "Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.",
            digits_compute=dp.get_precision('Account')),
        'hours_quantity':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Total Time',
            help=
            "Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."
        ),
        'last_invoice_date':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='date',
            string='Last Invoice Date',
            help=
            "If invoice from the costs, this is the date of the latest invoiced."
        ),
        'last_worked_invoiced_date':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='date',
            string='Date of Last Invoiced Cost',
            help=
            "If invoice from the costs, this is the date of the latest work or cost that have been invoiced."
        ),
        'last_worked_date':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type='date',
                        string='Date of Last Cost/Work',
                        help="Date of the latest work done on this account."),
        'hours_qtt_non_invoiced':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Uninvoiced Time',
            help=
            "Number of time (hours/days) (from journal of type 'general') that can be invoiced if you invoice based on analytic account."
        ),
        'hours_qtt_invoiced':
        fields.function(
            _hours_qtt_invoiced_calc,
            type='float',
            string='Invoiced Time',
            help=
            "Number of time (hours/days) that can be invoiced plus those that already have been invoiced."
        ),
        'remaining_hours':
        fields.function(
            _remaining_hours_calc,
            type='float',
            string='Remaining Time',
            help="Computed using the formula: Maximum Time - Total Time"),
        'remaining_ca':
        fields.function(
            _remaining_ca_calc,
            type='float',
            string='Remaining Revenue',
            help=
            "Computed using the formula: Max Invoice Price - Invoiced Amount.",
            digits_compute=dp.get_precision('Account')),
        'revenue_per_hour':
        fields.function(
            _revenue_per_hour_calc,
            type='float',
            string='Revenue per Time (real)',
            help="Computed using the formula: Invoiced Amount / Total Time",
            digits_compute=dp.get_precision('Account')),
        'real_margin':
        fields.function(
            _real_margin_calc,
            type='float',
            string='Real Margin',
            help="Computed using the formula: Invoiced Amount - Total Costs.",
            digits_compute=dp.get_precision('Account')),
        'theorical_margin':
        fields.function(
            _theorical_margin_calc,
            type='float',
            string='Theoretical Margin',
            help="Computed using the formula: Theorial Revenue - Total Costs",
            digits_compute=dp.get_precision('Account')),
        'real_margin_rate':
        fields.function(
            _real_margin_rate_calc,
            type='float',
            string='Real Margin Rate (%)',
            help=
            "Computes using the formula: (Real Margin / Total Costs) * 100.",
            digits_compute=dp.get_precision('Account')),
        'month_ids':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type='many2many',
                        relation='account_analytic_analysis.summary.month',
                        string='Month'),
        'user_ids':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type="many2many",
                        relation='account_analytic_analysis.summary.user',
                        string='User'),
    }
Ejemplo n.º 9
0
class report_intrastat(osv.osv):
    _name = "report.intrastat"
    _description = "Intrastat report"
    _auto = False
    _columns = {
        'name':
        fields.char('Year', size=64, required=False, readonly=True),
        'month':
        fields.selection([('01', 'January'), ('02', 'February'),
                          ('03', 'March'), ('04', 'April'), ('05', 'May'),
                          ('06', 'June'), ('07', 'July'), ('08', 'August'),
                          ('09', 'September'), ('10', 'October'),
                          ('11', 'November'), ('12', 'December')],
                         'Month',
                         readonly=True),
        'supply_units':
        fields.float('Supply Units', readonly=True),
        'ref':
        fields.char('Source document', size=64, readonly=True),
        'code':
        fields.char('Country code', size=2, readonly=True),
        'intrastat_id':
        fields.many2one('report.intrastat.code',
                        'Intrastat code',
                        readonly=True),
        'weight':
        fields.float('Weight', readonly=True),
        'value':
        fields.float('Value',
                     readonly=True,
                     digits_compute=dp.get_precision('Account')),
        'type':
        fields.selection([('import', 'Import'), ('export', 'Export')], 'Type'),
        'currency_id':
        fields.many2one('res.currency', "Currency", readonly=True),
    }

    def init(self, cr):
        drop_view_if_exists(cr, 'report_intrastat')
        cr.execute("""
            create or replace view report_intrastat as (
                select
                    to_char(inv.create_date, 'YYYY') as name,
                    to_char(inv.create_date, 'MM') as month,
                    min(inv_line.id) as id,
                    intrastat.id as intrastat_id,
                    upper(inv_country.code) as code,
                    sum(case when inv_line.price_unit is not null
                            then inv_line.price_unit * inv_line.quantity
                            else 0
                        end) as value,
                    sum(
                        case when uom.category_id != puom.category_id then (pt.weight_net * inv_line.quantity)
                        else (pt.weight_net * inv_line.quantity * uom.factor) end
                    ) as weight,
                    sum(
                        case when uom.category_id != puom.category_id then inv_line.quantity
                        else (inv_line.quantity * uom.factor) end
                    ) as supply_units,

                    inv.currency_id as currency_id,
                    inv.number as ref,
                    case when inv.type in ('out_invoice','in_refund')
                        then 'export'
                        else 'import'
                        end as type
                from
                    account_invoice inv
                    left join account_invoice_line inv_line on inv_line.invoice_id=inv.id
                    left join (product_template pt
                        left join product_product pp on (pp.product_tmpl_id = pt.id))
                    on (inv_line.product_id = pp.id)
                    left join product_uom uom on uom.id=inv_line.uos_id
                    left join product_uom puom on puom.id = pt.uom_id
                    left join report_intrastat_code intrastat on pt.intrastat_id = intrastat.id
                    left join (res_partner_address inv_address
                        left join res_country inv_country on (inv_country.id = inv_address.country_id))
                    on (inv_address.id = inv.address_invoice_id)

                where
                    inv.state in ('open','paid')
                    and inv_line.product_id is not null
                    and inv_country.intrastat=true
                group by to_char(inv.create_date, 'YYYY'), to_char(inv.create_date, 'MM'),intrastat.id,inv.type,pt.intrastat_id, inv_country.code,inv.number,  inv.currency_id
            )""")
Ejemplo n.º 10
0
class campaign_analysis(osv.osv):
    _name = "campaign.analysis"
    _description = "Campaign Analysis"
    _auto = False
    _rec_name = 'date'
    def _total_cost(self, cr, uid, ids, field_name, arg, context=None):
        """
            @param cr: the current row, from the database cursor,
            @param uid: the current user’s ID for security checks,
            @param ids: List of case and section Data’s IDs
            @param context: A standard dictionary for contextual values
        """
        result = {}
        for ca_obj in self.browse(cr, uid, ids, context=context):
            wi_ids = self.pool.get('marketing.campaign.workitem').search(cr, uid,
                        [('segment_id.campaign_id', '=', ca_obj.campaign_id.id)])
            total_cost = ca_obj.activity_id.variable_cost + \
                                ((ca_obj.campaign_id.fixed_cost or 1.00) / len(wi_ids))
            result[ca_obj.id] = total_cost
        return result
    _columns = {
        'res_id' : fields.integer('Resource', readonly=True),
        'year': fields.char('Year', size=4, readonly=True),
        'month': fields.selection([('01','January'), ('02','February'),
                                     ('03','March'), ('04','April'),('05','May'), ('06','June'),
                                     ('07','July'), ('08','August'), ('09','September'),
                                     ('10','October'), ('11','November'), ('12','December')],
                                  'Month', readonly=True),
        'day': fields.char('Day', size=10, readonly=True),
        'date': fields.date('Date', readonly=True, select=True),
        'campaign_id': fields.many2one('marketing.campaign', 'Campaign',
                                                                readonly=True),
        'activity_id': fields.many2one('marketing.campaign.activity', 'Activity',
                                                                 readonly=True),
        'segment_id': fields.many2one('marketing.campaign.segment', 'Segment',
                                                                readonly=True),
        'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
        'country_id': fields.related('partner_id', 'country_id',
                    type='many2one', relation='res.country',string='Country'),
        'total_cost' : fields.function(_total_cost, string='Cost',
                                    type="float", digits_compute=dp.get_precision('Purchase Price')),
        'revenue': fields.float('Revenue', readonly=True, digits_compute=dp.get_precision('Sale Price')),
        'count' : fields.integer('# of Actions', readonly=True),
        'state': fields.selection([('todo', 'To Do'),
                                   ('exception', 'Exception'), ('done', 'Done'),
                                   ('cancelled', 'Cancelled')], 'Status', readonly=True),
    }
    def init(self, cr):
        tools.drop_view_if_exists(cr, 'campaign_analysis')
        cr.execute("""
            create or replace view campaign_analysis as (
            select
                min(wi.id) as id,
                min(wi.res_id) as res_id,
                to_char(wi.date::date, 'YYYY') as year,
                to_char(wi.date::date, 'MM') as month,
                to_char(wi.date::date, 'YYYY-MM-DD') as day,
                wi.date::date as date,
                s.campaign_id as campaign_id,
                wi.activity_id as activity_id,
                wi.segment_id as segment_id,
                wi.partner_id as partner_id ,
                wi.state as state,
                sum(act.revenue) as revenue,
                count(*) as count
            from
                marketing_campaign_workitem wi
                left join res_partner p on (p.id=wi.partner_id)
                left join marketing_campaign_segment s on (s.id=wi.segment_id)
                left join marketing_campaign_activity act on (act.id= wi.activity_id)
            group by
                s.campaign_id,wi.activity_id,wi.segment_id,wi.partner_id,wi.state,
                wi.date::date
            )
        """)
Ejemplo n.º 11
0
class stock_product_moves(osv.osv):
    _name = "stock.product.moves"
    _description = "Product Stock Moves"
    _auto = False
    _order = "product_id, date"
    _columns = {
        'product_id':
        fields.many2one('product.product', 'Product', readonly=True),
        'picking_id':
        fields.many2one('stock.picking', 'Picking', readonly=True),
        'date':
        fields.datetime('Date', readonly=True),
        'partner_id':
        fields.many2one('res.partner', 'Partner', readonly=True),
        'invoice_id':
        fields.many2one('account.invoice', 'Invoice', readonly=True),
        'qty_received':
        fields.float(
            'Quantity Received',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            readonly=True),
        'qty_delivered':
        fields.float(
            'Quantity Delivered',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            readonly=True),
        'qty_stock':
        fields.float(
            'Quantity On Stock',
            digits_compute=dp.get_precision('Product Unit of Measure'),
            readonly=True),
        'price_unit':
        fields.float('Unit Price',
                     digits_compute=dp.get_precision('Product Price'),
                     readonly=True),
        'amount':
        fields.float('Amount',
                     digits_compute=dp.get_precision('Account'),
                     readonly=True)
    }

    def init(self, cr):
        drop_view_if_exists(cr, 'stock_product_moves')
        cr.execute("""CREATE OR REPLACE VIEW stock_product_moves AS
                      (SELECT sm.id AS id,
                              sm.product_id AS product_id,
                              sp.id AS picking_id,
                              sm.date AS date,
                              pa.id AS partner_id,
                              CASE
                                WHEN sp.type = 'in'
                                  THEN pai.id
                                WHEN sp.type = 'out'
                                  THEN sai.id
                                ELSE NULL
                              END AS invoice_id,
                              CASE
                                WHEN sp.type = 'in'
                                     OR sp.id IS NULL
                                  THEN sm.product_qty
                                ELSE NULL
                              END AS qty_received,
                              CASE
                                WHEN sp.type = 'out'
                                  THEN sm.product_qty
                                ELSE NULL
                              END AS qty_delivered,
                              (SELECT SUM(CASE
                                            WHEN sp1.type = 'in'
                                                 OR sp1.id IS NULL
                                              THEN sm1.product_qty
                                            ELSE sm1.product_qty * -1
                                          END)
                                 FROM stock_move AS sm1
                                      LEFT OUTER JOIN stock_picking AS sp1 ON sp1.id = sm1.picking_id
                                WHERE sm1.product_id = sm.product_id
                                      AND sm1.state = 'done'
                                      AND sm1.date <= sm.date) AS qty_stock,
                              sm.price_unit AS price_unit,
                              sm.product_qty * sm.price_unit AS amount
                         FROM stock_move AS sm
                              LEFT OUTER JOIN res_partner AS pa ON pa.id = sm.partner_id
                              LEFT OUTER JOIN stock_picking AS sp ON sp.id = sm.picking_id
                              LEFT OUTER JOIN sale_order_line_invoice_rel AS solir ON solir.order_line_id = sm.sale_line_id
                              LEFT OUTER JOIN purchase_order_line_invoice_rel AS polir ON polir.order_line_id = sm.purchase_line_id
                              LEFT OUTER JOIN account_invoice_line AS sail ON sail.id = solir.invoice_id
                              LEFT OUTER JOIN account_invoice AS sai ON sai.id = sail.invoice_id
                              LEFT OUTER JOIN account_invoice_line AS pail ON pail.id = polir.invoice_id
                              LEFT OUTER JOIN account_invoice AS pai ON pai.id = pail.invoice_id
                        WHERE sm.state = 'done');""")
Ejemplo n.º 12
0
class hr_expense_report(osv.osv):
    _name = "hr.expense.report"
    _description = "Expenses Statistics"
    _auto = False
    _rec_name = 'date'
    _columns = {
        'date': fields.date('Date ', readonly=True),
        'year': fields.char('Year', size=4, readonly=True),
        'day': fields.char('Day', size=128, readonly=True),
        'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
            ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
            ('10','October'), ('11','November'), ('12','December')], 'Month',readonly=True),
        'product_id':fields.many2one('product.product', 'Product', readonly=True),
        'journal_id': fields.many2one('account.journal', 'Force Journal', readonly=True),
        'product_qty':fields.float('Qty', readonly=True),
        'invoiced':fields.integer('# of Invoiced Lines', readonly=True),
        'employee_id': fields.many2one('hr.employee', "Employee's Name", readonly=True),
        'date_confirm': fields.date('Confirmation Date', readonly=True),
        'date_valid': fields.date('Validation Date', readonly=True),
        'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True),
        'department_id':fields.many2one('hr.department','Department', readonly=True),
        'company_id':fields.many2one('res.company', 'Company', readonly=True),
        'user_id':fields.many2one('res.users', 'Validation User', readonly=True),
        'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
        'price_total':fields.float('Total Price', readonly=True, digits_compute=dp.get_precision('Account')),
        'delay_valid':fields.float('Delay to Valid', readonly=True),
        'delay_confirm':fields.float('Delay to Confirm', readonly=True),
        'analytic_account': fields.many2one('account.analytic.account','Analytic account',readonly=True),
        'price_average':fields.float('Average Price', readonly=True, digits_compute=dp.get_precision('Account')),
        'nbr':fields.integer('# of Lines', readonly=True),
        'no_of_products':fields.integer('# of Products', readonly=True),
        'no_of_account':fields.integer('# of Accounts', readonly=True),
        'state': fields.selection([
            ('draft', 'Draft'),
            ('confirm', 'Waiting confirmation'),
            ('accepted', 'Accepted'),
            ('invoiced', 'Invoiced'),
            ('paid', 'Reimbursed'),
            ('cancelled', 'Cancelled')],
            'Status', readonly=True),
    }
    _order = 'date desc'
    def init(self, cr):
        tools.drop_view_if_exists(cr, 'hr_expense_report')
        cr.execute("""
            create or replace view hr_expense_report as (
                 select
                     min(l.id) as id,
                     date_trunc('day',s.date) as date,
                     s.employee_id,
                     s.journal_id,
                     s.currency_id,
                     to_date(to_char(s.date_confirm, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_confirm,
                     to_date(to_char(s.date_valid, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_valid,
                     s.invoice_id,
                     count(s.invoice_id) as invoiced,
                     s.user_valid as user_id,
                     s.department_id,
                     to_char(date_trunc('day',s.create_date), 'YYYY') as year,
                     to_char(date_trunc('day',s.create_date), 'MM') as month,
                     to_char(date_trunc('day',s.create_date), 'YYYY-MM-DD') as day,
                     avg(extract('epoch' from age(s.date_valid,s.date)))/(3600*24) as  delay_valid,
                     avg(extract('epoch' from age(s.date_valid,s.date_confirm)))/(3600*24) as  delay_confirm,
                     l.product_id as product_id,
                     l.analytic_account as analytic_account,
                     sum(l.unit_quantity * u.factor) as product_qty,
                     s.company_id as company_id,
                     sum(l.unit_quantity*l.unit_amount) as price_total,
                     (sum(l.unit_quantity*l.unit_amount)/sum(case when l.unit_quantity=0 or u.factor=0 then 1 else l.unit_quantity * u.factor end))::decimal(16,2) as price_average,
                     count(*) as nbr,
                     (select unit_quantity from hr_expense_line where id=l.id and product_id is not null) as no_of_products,
                     (select analytic_account from hr_expense_line where id=l.id and analytic_account is not null) as no_of_account,
                     s.state
                 from hr_expense_line l
                 left join hr_expense_expense s on (s.id=l.expense_id)
                 left join product_uom u on (u.id=l.uom_id)
                 group by
                     date_trunc('day',s.date),
                     to_char(date_trunc('day',s.create_date), 'YYYY'),
                     to_char(date_trunc('day',s.create_date), 'MM'),
                     to_char(date_trunc('day',s.create_date), 'YYYY-MM-DD'),
                     to_date(to_char(s.date_confirm, 'dd-MM-YYYY'),'dd-MM-YYYY'),
                     to_date(to_char(s.date_valid, 'dd-MM-YYYY'),'dd-MM-YYYY'),
                     l.product_id,
                     l.analytic_account,
                     s.invoice_id,
                     s.currency_id,
                     s.user_valid,
                     s.department_id,
                     l.uom_id,
                     l.id,
                     s.state,
                     s.journal_id,
                     s.company_id,
                     s.employee_id
            )
        """)
Ejemplo n.º 13
0
class hr_recruitment_report(osv.osv):
    _name = "hr.recruitment.report"
    _description = "Recruitments Statistics"
    _auto = False
    _rec_name = 'date'

    _columns = {
        'user_id': fields.many2one('res.users', 'User', readonly=True),
        'nbr': fields.integer('# of Cases', readonly=True),
        'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True),
        'month':fields.selection([('01', 'January'), ('02', 'February'), \
                                  ('03', 'March'), ('04', 'April'),\
                                  ('05', 'May'), ('06', 'June'), \
                                  ('07', 'July'), ('08', 'August'),\
                                  ('09', 'September'), ('10', 'October'),\
                                  ('11', 'November'), ('12', 'December')], 'Month', readonly=True),
        'company_id': fields.many2one('res.company', 'Company', readonly=True),
        'day': fields.char('Day', size=128, readonly=True),
        'year': fields.char('Year', size=4, readonly=True),
        'date': fields.date('Date', readonly=True),
        'date_closed': fields.date('Closed', readonly=True),
        'job_id': fields.many2one('hr.job', 'Applied Job',readonly=True),
        'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage'),
        'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
        'department_id': fields.many2one('hr.department','Department',readonly=True),
        'priority': fields.selection(hr_recruitment.AVAILABLE_PRIORITIES, 'Appreciation'),
        'salary_prop' : fields.float("Salary Proposed", digits_compute=dp.get_precision('Account')),
        'salary_prop_avg' : fields.float("Avg Salary Proposed", group_operator="avg", digits_compute=dp.get_precision('Account')),
        'salary_exp' : fields.float("Salary Expected", digits_compute=dp.get_precision('Account')),
        'partner_id': fields.many2one('res.partner', 'Partner',readonly=True),
        'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact Name',readonly=True),
        'available': fields.float("Availability"),
        'delay_open': fields.float('Avg. Delay to Open', digits=(16,2), readonly=True, group_operator="avg",
                                       help="Number of Days to close the project issue"),
        'delay_close': fields.float('Avg. Delay to Close', digits=(16,2), readonly=True, group_operator="avg",
                                       help="Number of Days to close the project issue"),
    }
    _order = 'date desc'

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'hr_recruitment_report')
        cr.execute("""
            create or replace view hr_recruitment_report as (
                 select
                     min(s.id) as id,
                     date_trunc('day',s.create_date) as date,
                     date_trunc('day',s.date_closed) as date_closed,
                     to_char(s.create_date, 'YYYY') as year,
                     to_char(s.create_date, 'MM') as month,
                     to_char(s.create_date, 'YYYY-MM-DD') as day,
                     s.state,
                     s.partner_id,
                     s.company_id,
                     s.partner_address_id,
                     s.user_id,
                     s.job_id,
                     s.type_id,
                     sum(s.availability) as available,
                     s.department_id,
                     s.priority,
                     s.stage_id,
                     sum(salary_proposed) as salary_prop,
                     (sum(salary_proposed)/count(*)) as salary_prop_avg,
                     sum(salary_expected) as salary_exp,
                     extract('epoch' from (s.date_open-s.create_date))/(3600*24) as  delay_open,
                     extract('epoch' from (s.date_closed-s.create_date))/(3600*24) as  delay_close,
                     count(*) as nbr
                 from hr_applicant s
                 group by
                     to_char(s.create_date, 'YYYY'),
                     to_char(s.create_date, 'MM'),
                     to_char(s.create_date, 'YYYY-MM-DD') ,
                     date_trunc('day',s.create_date),
                     date_trunc('day',s.date_closed),
                     s.date_open,
                     s.create_date,
                     s.date_closed,
                     s.state,
                     s.partner_id,
                     s.partner_address_id,
                     s.company_id,
                     s.user_id,
                     s.stage_id,
                     s.type_id,
                     s.priority,
                     s.job_id,
                     s.department_id
            )
        """)
class account_analytic_account(osv.osv):
    _name = "account.analytic.account"
    _inherit = "account.analytic.account"

    def _analysis_all(self, cr, uid, ids, fields, arg, context=None):
        dp = 2
        res = dict([(i, {}) for i in ids])
        parent_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        accounts = self.browse(cr, uid, ids, context=context)

        for f in fields:
            if f == 'user_ids':
                cr.execute('SELECT MAX(id) FROM res_users')
                max_user = cr.fetchone()[0]
                if parent_ids:
                    cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user ' \
                               'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
                    result = cr.fetchall()
                else:
                    result = []
                for id in ids:
                    res[id][f] = [int((id * max_user) + x[0]) for x in result]
            elif f == 'month_ids':
                if parent_ids:
                    cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month ' \
                               'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
                    result = cr.fetchall()
                else:
                    result = []
                for id in ids:
                    res[id][f] = [
                        int(id * 1000000 + int(x[0])) for x in result
                    ]
            elif f == 'last_worked_invoiced_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, MAX(date) \
                            FROM account_analytic_line \
                            WHERE account_id IN %s \
                                AND invoice_id IS NOT NULL \
                            GROUP BY account_analytic_line.account_id;",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = sum
            elif f == 'ca_to_invoice':
                for id in ids:
                    res[id][f] = 0.0
                res2 = {}
                if parent_ids:
                    # Amount uninvoiced hours to invoice at sale price
                    # Warning
                    # This computation doesn't take care of pricelist !
                    # Just consider list_price
                    cr.execute(
                        """SELECT account_analytic_account.id, \
                                COALESCE(SUM (product_template.list_price * \
                                    account_analytic_line.unit_amount * \
                                    ((100-hr_timesheet_invoice_factor.factor)/100)), 0.0) \
                                    AS ca_to_invoice \
                            FROM product_template \
                            JOIN product_product \
                                ON product_template.id = product_product.product_tmpl_id \
                            JOIN account_analytic_line \
                                ON account_analytic_line.product_id = product_product.id \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            JOIN account_analytic_account \
                                ON account_analytic_account.id = account_analytic_line.account_id \
                            JOIN hr_timesheet_invoice_factor \
                                ON hr_timesheet_invoice_factor.id = account_analytic_account.to_invoice \
                            WHERE account_analytic_account.id IN %s \
                                AND account_analytic_line.invoice_id IS NULL \
                                AND account_analytic_line.to_invoice IS NOT NULL \
                                AND account_analytic_journal.type = 'general' \
                            GROUP BY account_analytic_account.id;""",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(sum, dp)

                # sum both result on account_id
                for id in ids:
                    res[id][f] = round(res.get(id, {}).get(f, 0.0),
                                       dp) + round(res2.get(id, 0.0), 2)
            elif f == 'last_invoice_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, \
                                DATE(MAX(account_invoice.date_invoice)) \
                            FROM account_analytic_line \
                            JOIN account_invoice \
                                ON account_analytic_line.invoice_id = account_invoice.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_line.invoice_id IS NOT NULL \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    for account_id, lid in cr.fetchall():
                        res[account_id][f] = lid
            elif f == 'last_worked_date':
                for id in ids:
                    res[id][f] = False
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, MAX(date) \
                            FROM account_analytic_line \
                            WHERE account_id IN %s \
                                AND invoice_id IS NULL \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    for account_id, lwd in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = lwd
            elif f == 'hours_qtt_non_invoiced':
                for id in ids:
                    res[id][f] = 0.0
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
                            FROM account_analytic_line \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_journal.type='general' \
                                AND invoice_id IS NULL \
                                AND to_invoice IS NOT NULL \
                            GROUP BY account_analytic_line.account_id;",
                        (parent_ids, ))
                    for account_id, sua in cr.fetchall():
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(sua, dp)
                for id in ids:
                    res[id][f] = round(res[id][f], dp)
            elif f == 'hours_quantity':
                for id in ids:
                    res[id][f] = 0.0
                if parent_ids:
                    cr.execute(
                        "SELECT account_analytic_line.account_id, COALESCE(SUM(unit_amount), 0.0) \
                            FROM account_analytic_line \
                            JOIN account_analytic_journal \
                                ON account_analytic_line.journal_id = account_analytic_journal.id \
                            WHERE account_analytic_line.account_id IN %s \
                                AND account_analytic_journal.type='general' \
                            GROUP BY account_analytic_line.account_id",
                        (parent_ids, ))
                    ff = cr.fetchall()
                    for account_id, hq in ff:
                        if account_id not in res:
                            res[account_id] = {}
                        res[account_id][f] = round(hq, dp)
                for id in ids:
                    res[id][f] = round(res[id][f], dp)
            elif f == 'ca_theorical':
                # TODO Take care of pricelist and purchase !
                for id in ids:
                    res[id][f] = 0.0
                # Warning
                # This computation doesn't take care of pricelist !
                # Just consider list_price
                if parent_ids:
                    cr.execute(
                        """SELECT account_analytic_line.account_id AS account_id, \
                                COALESCE(SUM((account_analytic_line.unit_amount * pt.list_price) \
                                    - (account_analytic_line.unit_amount * pt.list_price \
                                        * hr.factor)), 0.0) AS somme
                            FROM account_analytic_line \
                            LEFT JOIN account_analytic_journal \
                                ON (account_analytic_line.journal_id = account_analytic_journal.id) \
                            JOIN product_product pp \
                                ON (account_analytic_line.product_id = pp.id) \
                            JOIN product_template pt \
                                ON (pp.product_tmpl_id = pt.id) \
                            JOIN account_analytic_account a \
                                ON (a.id=account_analytic_line.account_id) \
                            JOIN hr_timesheet_invoice_factor hr \
                                ON (hr.id=a.to_invoice) \
                        WHERE account_analytic_line.account_id IN %s \
                            AND a.to_invoice IS NOT NULL \
                            AND account_analytic_journal.type IN ('purchase', 'general')
                        GROUP BY account_analytic_line.account_id""",
                        (parent_ids, ))
                    for account_id, sum in cr.fetchall():
                        res[account_id][f] = round(sum, dp)
        return res

    def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        res_final = {}
        child_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        for i in child_ids:
            res[i] = 0.0
        if not child_ids:
            return res

        if child_ids:
            cr.execute(
                "SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) \
                    FROM account_analytic_line \
                    JOIN account_analytic_journal \
                        ON account_analytic_line.journal_id = account_analytic_journal.id  \
                    WHERE account_analytic_line.account_id IN %s \
                        AND account_analytic_journal.type = 'sale' \
                    GROUP BY account_analytic_line.account_id", (child_ids, ))
            for account_id, sum in cr.fetchall():
                res[account_id] = round(sum, 2)
        res_final = res
        return res_final

    def _total_cost_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        res_final = {}
        child_ids = tuple(
            ids
        )  #We don't want consolidation for each of these fields because those complex computation is resource-greedy.
        for i in child_ids:
            res[i] = 0.0
        if not child_ids:
            return res
        if child_ids:
            cr.execute(
                """SELECT account_analytic_line.account_id, COALESCE(SUM(amount), 0.0) \
                    FROM account_analytic_line \
                    JOIN account_analytic_journal \
                        ON account_analytic_line.journal_id = account_analytic_journal.id \
                    WHERE account_analytic_line.account_id IN %s \
                        AND amount<0 \
                    GROUP BY account_analytic_line.account_id""",
                (child_ids, ))
            for account_id, sum in cr.fetchall():
                res[account_id] = round(sum, 2)
        res_final = res
        return res_final

    def _remaining_hours_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.quantity_max != 0:
                res[account.id] = account.quantity_max - account.hours_quantity
            else:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _remaining_hours_to_invoice_calc(self,
                                         cr,
                                         uid,
                                         ids,
                                         name,
                                         arg,
                                         context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = max(
                account.hours_qtt_est - account.timesheet_ca_invoiced,
                account.ca_to_invoice)
        return res

    def _hours_qtt_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.
                id] = account.hours_quantity - account.hours_qtt_non_invoiced
            if res[account.id] < 0:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _revenue_per_hour_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.hours_qtt_invoiced == 0:
                res[account.id] = 0.0
            else:
                res[account.
                    id] = account.ca_invoiced / account.hours_qtt_invoiced
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _real_margin_rate_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            if account.ca_invoiced == 0:
                res[account.id] = 0.0
            elif account.total_cost != 0.0:
                res[account.
                    id] = -(account.real_margin / account.total_cost) * 100
            else:
                res[account.id] = 0.0
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _fix_price_to_invoice_calc(self,
                                   cr,
                                   uid,
                                   ids,
                                   name,
                                   arg,
                                   context=None):
        sale_obj = self.pool.get('sale.order')
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = 0.0
            sale_ids = sale_obj.search(
                cr,
                uid, [('project_id', '=', account.id),
                      ('partner_id', '=', account.partner_id.id)],
                context=context)
            for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
                if not sale.invoiced:
                    res[account.id] += sale.amount_untaxed
                    for invoice in sale.invoice_ids:
                        if invoice.state not in ('draft', 'cancel'):
                            res[account.id] -= invoice.amount_untaxed
        return res

    def _timesheet_ca_invoiced_calc(self,
                                    cr,
                                    uid,
                                    ids,
                                    name,
                                    arg,
                                    context=None):
        lines_obj = self.pool.get('account.analytic.line')
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = 0.0
            line_ids = lines_obj.search(cr,
                                        uid,
                                        [('account_id', '=', account.id),
                                         ('invoice_id', '!=', False),
                                         ('to_invoice', '!=', False),
                                         ('journal_id.type', '=', 'general')],
                                        context=context)
            for line in lines_obj.browse(cr, uid, line_ids, context=context):
                res[account.id] += line.invoice_id.amount_untaxed
        return res

    def _remaining_ca_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = max(account.amount_max - account.ca_invoiced,
                                  account.fix_price_to_invoice)
        return res

    def _real_margin_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = account.ca_invoiced + account.total_cost
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _theorical_margin_calc(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id] = account.ca_theorical + account.total_cost
        for id in ids:
            res[id] = round(res.get(id, 0.0), 2)
        return res

    def _is_overdue_quantity(self,
                             cr,
                             uid,
                             ids,
                             fieldnames,
                             args,
                             context=None):
        result = dict.fromkeys(ids, 0)
        for record in self.browse(cr, uid, ids, context=context):
            if record.quantity_max > 0.0:
                result[record.id] = int(
                    record.hours_quantity >= record.quantity_max)
            else:
                result[record.id] = 0
        return result

    def _get_analytic_account(self, cr, uid, ids, context=None):
        result = set()
        for line in self.pool.get('account.analytic.line').browse(
                cr, uid, ids, context=context):
            result.add(line.account_id.id)
        return list(result)

    def _get_total_estimation(self, account):
        tot_est = 0.0
        if account.fix_price_invoices:
            tot_est += account.amount_max
        if account.invoice_on_timesheets:
            tot_est += account.hours_qtt_est
        return tot_est

    def _get_total_invoiced(self, account):
        total_invoiced = 0.0
        if account.fix_price_invoices:
            total_invoiced += account.ca_invoiced
        if account.invoice_on_timesheets:
            total_invoiced += account.timesheet_ca_invoiced
        return total_invoiced

    def _get_total_remaining(self, account):
        total_remaining = 0.0
        if account.fix_price_invoices:
            total_remaining += account.remaining_ca
        if account.invoice_on_timesheets:
            total_remaining += account.remaining_hours_to_invoice
        return total_remaining

    def _get_total_toinvoice(self, account):
        total_toinvoice = 0.0
        if account.fix_price_invoices:
            total_toinvoice += account.fix_price_to_invoice
        if account.invoice_on_timesheets:
            total_toinvoice += account.ca_to_invoice
        return total_toinvoice

    def _sum_of_fields(self, cr, uid, ids, name, arg, context=None):
        res = dict([(i, {}) for i in ids])
        for account in self.browse(cr, uid, ids, context=context):
            res[account.id]['est_total'] = self._get_total_estimation(account)
            res[account.id]['invoiced_total'] = self._get_total_invoiced(
                account)
            res[account.id]['remaining_total'] = self._get_total_remaining(
                account)
            res[account.id]['toinvoice_total'] = self._get_total_toinvoice(
                account)
        return res

    _columns = {
        'is_overdue_quantity':
        fields.function(_is_overdue_quantity,
                        method=True,
                        type='boolean',
                        string='Overdue Quantity',
                        store={
                            'account.analytic.line':
                            (_get_analytic_account, None, 20),
                        }),
        'ca_invoiced':
        fields.function(
            _ca_invoiced_calc,
            type='float',
            string='Invoiced Amount',
            help="Total customer invoiced amount for this account.",
            digits_compute=dp.get_precision('Account')),
        'total_cost':
        fields.function(
            _total_cost_calc,
            type='float',
            string='Total Costs',
            help=
            "Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets.",
            digits_compute=dp.get_precision('Account')),
        'ca_to_invoice':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Uninvoiced Amount',
            help=
            "If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs.",
            digits_compute=dp.get_precision('Account')),
        'ca_theorical':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Theoretical Revenue',
            help=
            "Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.",
            digits_compute=dp.get_precision('Account')),
        'hours_quantity':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Total Worked Time',
            help=
            "Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."
        ),
        'last_invoice_date':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='date',
            string='Last Invoice Date',
            help=
            "If invoice from the costs, this is the date of the latest invoiced."
        ),
        'last_worked_invoiced_date':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='date',
            string='Date of Last Invoiced Cost',
            help=
            "If invoice from the costs, this is the date of the latest work or cost that have been invoiced."
        ),
        'last_worked_date':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type='date',
                        string='Date of Last Cost/Work',
                        help="Date of the latest work done on this account."),
        'hours_qtt_non_invoiced':
        fields.function(
            _analysis_all,
            multi='analytic_analysis',
            type='float',
            string='Uninvoiced Time',
            help=
            "Number of time (hours/days) (from journal of type 'general') that can be invoiced if you invoice based on analytic account."
        ),
        'hours_qtt_invoiced':
        fields.function(
            _hours_qtt_invoiced_calc,
            type='float',
            string='Invoiced Time',
            help=
            "Number of time (hours/days) that can be invoiced plus those that already have been invoiced."
        ),
        'remaining_hours':
        fields.function(
            _remaining_hours_calc,
            type='float',
            string='Remaining Time',
            help="Computed using the formula: Maximum Time - Total Worked Time"
        ),
        'remaining_hours_to_invoice':
        fields.function(
            _remaining_hours_to_invoice_calc,
            type='float',
            string='Remaining Time',
            help=
            "Computed using the formula: Maximum Time - Total Invoiced Time"),
        'fix_price_to_invoice':
        fields.function(_fix_price_to_invoice_calc,
                        type='float',
                        string='Remaining Time',
                        help="Sum of quotations for this contract."),
        'timesheet_ca_invoiced':
        fields.function(
            _timesheet_ca_invoiced_calc,
            type='float',
            string='Remaining Time',
            help="Sum of timesheet lines invoiced for this contract."),
        'remaining_ca':
        fields.function(
            _remaining_ca_calc,
            type='float',
            string='Remaining Revenue',
            help=
            "Computed using the formula: Max Invoice Price - Invoiced Amount.",
            digits_compute=dp.get_precision('Account')),
        'revenue_per_hour':
        fields.function(
            _revenue_per_hour_calc,
            type='float',
            string='Revenue per Time (real)',
            help="Computed using the formula: Invoiced Amount / Total Time",
            digits_compute=dp.get_precision('Account')),
        'real_margin':
        fields.function(
            _real_margin_calc,
            type='float',
            string='Real Margin',
            help="Computed using the formula: Invoiced Amount - Total Costs.",
            digits_compute=dp.get_precision('Account')),
        'theorical_margin':
        fields.function(
            _theorical_margin_calc,
            type='float',
            string='Theoretical Margin',
            help=
            "Computed using the formula: Theoretical Revenue - Total Costs",
            digits_compute=dp.get_precision('Account')),
        'real_margin_rate':
        fields.function(
            _real_margin_rate_calc,
            type='float',
            string='Real Margin Rate (%)',
            help=
            "Computes using the formula: (Real Margin / Total Costs) * 100.",
            digits_compute=dp.get_precision('Account')),
        'fix_price_invoices':
        fields.boolean('Fix Price Invoices'),
        'invoice_on_timesheets':
        fields.boolean("Invoice On Timesheets"),
        'month_ids':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type='many2many',
                        relation='account_analytic_analysis.summary.month',
                        string='Month'),
        'user_ids':
        fields.function(_analysis_all,
                        multi='analytic_analysis',
                        type="many2many",
                        relation='account_analytic_analysis.summary.user',
                        string='User'),
        'hours_qtt_est':
        fields.float('Estimation of Hours to Invoice'),
        'est_total':
        fields.function(_sum_of_fields,
                        type="float",
                        multi="sum_of_all",
                        string="Total Estimation"),
        'invoiced_total':
        fields.function(_sum_of_fields,
                        type="float",
                        multi="sum_of_all",
                        string="Total Invoiced"),
        'remaining_total':
        fields.function(
            _sum_of_fields,
            type="float",
            multi="sum_of_all",
            string="Total Remaining",
            help=
            "Expectation of remaining income for this contract. Computed as the sum of remaining subtotals which, in turn, are computed as the maximum between '(Estimation - Invoiced)' and 'To Invoice' amounts"
        ),
        'toinvoice_total':
        fields.function(
            _sum_of_fields,
            type="float",
            multi="sum_of_all",
            string="Total to Invoice",
            help=" Sum of everything that could be invoiced for this contract."
        ),
    }

    def open_sale_order_lines(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        sale_ids = self.pool.get('sale.order').search(
            cr, uid,
            [('project_id', '=', context.get('search_default_project_id',
                                             False)),
             ('partner_id', '=', context.get('search_default_partner_id',
                                             False))])
        names = [
            record.name
            for record in self.browse(cr, uid, ids, context=context)
        ]
        name = _('Sale Order Lines of %s') % ','.join(names)
        return {
            'type': 'ir.actions.act_window',
            'name': name,
            'view_type': 'form',
            'view_mode': 'tree,form',
            'context': context,
            'domain': [('order_id', 'in', sale_ids)],
            'res_model': 'sale.order.line',
            'nodestroy': True,
        }

    def on_change_template(self, cr, uid, ids, template_id, context=None):
        if not template_id:
            return {}
        res = super(account_analytic_account,
                    self).on_change_template(cr,
                                             uid,
                                             ids,
                                             template_id,
                                             context=context)
        if template_id and 'value' in res:
            template = self.browse(cr, uid, template_id, context=context)
            res['value']['fix_price_invoices'] = template.fix_price_invoices
            res['value'][
                'invoice_on_timesheets'] = template.invoice_on_timesheets
            res['value']['hours_qtt_est'] = template.hours_qtt_est
            res['value']['amount_max'] = template.amount_max
            res['value']['to_invoice'] = template.to_invoice.id
            res['value']['pricelist_id'] = template.pricelist_id.id
        return res
Ejemplo n.º 15
0
class marketing_campaign(osv.osv):
    _name = "marketing.campaign"
    _description = "Marketing Campaign"

    _columns = {
        'name': fields.char('Name', size=64, required=True),
        'object_id': fields.many2one('ir.model', 'Resource', required=True,
                                      help="Choose the resource on which you want \
this campaign to be run"                        ),
        'partner_field_id': fields.many2one('ir.model.fields', 'Partner Field',
                                            domain="[('model_id', '=', object_id), ('ttype', '=', 'many2one'), ('relation', '=', 'res.partner')]",
                                            help="The generated workitems will be linked to the partner related to the record. If the record is the partner itself leave this field empty."),
        'mode': fields.selection([('test', 'Test Directly'),
                                ('test_realtime', 'Test in Realtime'),
                                ('manual', 'With Manual Confirmation'),
                                ('active', 'Normal')],
                                 'Mode', required=True, help= \
"""Test - It creates and process all the activities directly (without waiting for the delay on transitions) but does not send emails or produce reports.
Test in Realtime - It creates and processes all the activities directly but does not send emails or produce reports.
With Manual Confirmation - the campaigns runs normally, but the user has to validate all workitem manually.
Normal - the campaign runs normally and automatically sends all emails and reports (be very careful with this mode, you're live!)"""),
        'state': fields.selection([('draft', 'Draft'),
                                   ('running', 'Running'),
                                   ('done', 'Done'),
                                   ('cancelled', 'Cancelled'),],
                                   'State',),
        'activity_ids': fields.one2many('marketing.campaign.activity',
                                       'campaign_id', 'Activities'),
        'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for running this campaign. You may also specify variable cost and revenue on each campaign activity. Cost and Revenue statistics are included in Campaign Reporting.", digits_compute=dp.get_precision('Purchase Price')),
    }

    _defaults = {
        'state': lambda *a: 'draft',
        'mode': lambda *a: 'test',
    }

    def state_running_set(self, cr, uid, ids, *args):
        # TODO check that all subcampaigns are running
        campaign = self.browse(cr, uid, ids[0])

        if not campaign.activity_ids:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be started: there are no activities in it"
                  ))

        has_start = False
        has_signal_without_from = False

        for activity in campaign.activity_ids:
            if activity.start:
                has_start = True
            if activity.signal and len(activity.from_ids) == 0:
                has_signal_without_from = True

            if activity.type != 'email':
                continue
            if not activity.email_template_id.from_account:
                raise osv.except_osv(
                    _("Error"),
                    _("The campaign cannot be started: the email account is missing in email activity '%s'"
                      ) % activity.name)
            if activity.email_template_id.from_account.state != 'approved':
                raise osv.except_osv(
                    _("Error"),
                    _("The campaign cannot be started: the email account is not approved in email activity '%s'"
                      ) % activity.name)

        if not has_start and not has_signal_without_from:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be started: it doesn't have any starting activity (or any activity with a signal and no previous activity)"
                  ))

        return self.write(cr, uid, ids, {'state': 'running'})

    def state_done_set(self, cr, uid, ids, *args):
        # TODO check that this campaign is not a subcampaign in running mode.
        segment_ids = self.pool.get('marketing.campaign.segment').search(
            cr, uid, [('campaign_id', 'in', ids), ('state', '=', 'running')])
        if segment_ids:
            raise osv.except_osv(
                _("Error"),
                _("The campaign cannot be marked as done before all segments are done"
                  ))
        self.write(cr, uid, ids, {'state': 'done'})
        return True

    def state_cancel_set(self, cr, uid, ids, *args):
        # TODO check that this campaign is not a subcampaign in running mode.
        self.write(cr, uid, ids, {'state': 'cancelled'})
        return True

    def signal(self,
               cr,
               uid,
               model,
               res_id,
               signal,
               run_existing=True,
               context=None):
        record = self.pool.get(model).browse(cr, uid, res_id, context)
        return self._signal(cr, uid, record, signal, run_existing, context)

    def _signal(self,
                cr,
                uid,
                record,
                signal,
                run_existing=True,
                context=None):
        if not signal:
            raise ValueError('signal cannot be False')

        Workitems = self.pool.get('marketing.campaign.workitem')
        domain = [('object_id.model', '=', record._table._name),
                  ('state', '=', 'running')]
        campaign_ids = self.search(cr, uid, domain, context=context)
        for campaign in self.browse(cr, uid, campaign_ids, context=context):
            for activity in campaign.activity_ids:
                if activity.signal != signal:
                    continue

                data = dict(activity_id=activity.id,
                            res_id=record.id,
                            state='todo')
                wi_domain = [(k, '=', v) for k, v in data.items()]

                wi_ids = Workitems.search(cr, uid, wi_domain, context=context)
                if wi_ids:
                    if not run_existing:
                        continue
                else:
                    partner = self._get_partner_for(campaign, record)
                    if partner:
                        data['partner_id'] = partner.id
                    wi_id = Workitems.create(cr, uid, data, context=context)
                    wi_ids = [wi_id]
                Workitems.process(cr, uid, wi_ids, context=context)
        return True

    def _get_partner_for(self, campaign, record):
        partner_field = campaign.partner_field_id.name
        if partner_field:
            return getattr(record, partner_field)
        elif campaign.object_id.model == 'res.partner':
            return record
        return None

    # prevent duplication until the server properly duplicates several levels of nested o2m
    def copy(self, cr, uid, id, default=None, context=None):
        raise osv.except_osv(
            _("Operation not supported"),
            _("Sorry, campaign duplication is not supported at the moment."))
Ejemplo n.º 16
0
class intrastat(osv.osv):
    _name = "intrastat"
    _description = "Intrastat report"
    _auto = False
    _columns = {
        'intrastat_id':
        fields.many2one('intrastat.code', 'Intrastat code', readonly=True),
        'intrastat_name':
        fields.related('intrastat_id',
                       'description',
                       type='char',
                       string='Intrastat name'),
        'country_supplier':
        fields.many2one('res.country', 'Country of supplier', readonly=True),
        'country_supplier_code':
        fields.related('country_supplier',
                       'code',
                       type='char',
                       string='Country of suppl.code'),
        'transaction_type_id':
        fields.many2one('intrastat.transaction.type',
                        'Transaction type',
                        readonly=True),
        'transaction_type_code':
        fields.related('transaction_type_id',
                       'code',
                       type='char',
                       string='Trans. type'),
        'country_origin':
        fields.many2one('res.country', 'Country of origin', readonly=True),
        'country_origin_code':
        fields.related('country_origin',
                       'code',
                       type='char',
                       string='Country of origin'),
        'weight':
        fields.float('Weight', readonly=True),
        'value':
        fields.float('Value',
                     readonly=True,
                     digits_compute=dp.get_precision('Account')),
        'date':
        fields.char('Date done', size=64, required=False, readonly=True),
        'month':
        fields.selection([('01', 'January'), ('02', 'February'),
                          ('03', 'March'), ('04', 'April'), ('05', 'May'),
                          ('06', 'June'), ('07', 'July'), ('08', 'August'),
                          ('09', 'September'), ('10', 'October'),
                          ('11', 'November'), ('12', 'December')],
                         'Month',
                         readonly=True),
        'year':
        fields.char('Year', size=64, required=False, readonly=True),
    }

    def init(self, cr):
        drop_view_if_exists(cr, 'intrastat')
        cr.execute("""
            create or replace view intrastat as (
                select
                    MIN (SM.id) AS id,
                    to_char(SP.date_done, 'YYYY') || '-' || to_char(SP.date_done, 'MM') as date,
                    to_char(SP.date_done, 'MM') as month,
                    to_char(SP.date_done, 'YYYY') as year,
                    SP.transaction_type_id as transaction_type_id,
                    PT.intrastat_id AS intrastat_id,
                    SUM (SM.product_qty * PT.weight_net) AS weight,
                    SUM (SM.product_qty * SM.price_unit) AS value,
                    SM.country_origin_id AS country_origin,
                    PA.country_id AS country_supplier
                from
                    stock_picking SP
                    left join stock_move SM on SM.picking_id=SP.id
                    left join (product_template PT
                        left join product_product PP on (PP.product_tmpl_id = PT.id))
                        on (SM.product_id = PP.id)
                    left join res_partner PA on PA.id = SP.partner_id
                    left join res_country C on C.id = PA.country_id
                where
                    SP.state = 'done' AND PA.country_id != 201 AND SP.type = 'in' AND C.intrastat = true
                group by to_char(SP.date_done, 'YYYY') || '-' || to_char(SP.date_done, 'MM'), to_char(SP.date_done, 'MM'), to_char(SP.date_done, 'YYYY'),
                    SP.transaction_type_id, PT.intrastat_id, SM.country_origin_id, PA.country_id
            )""")