<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2004-2012 Pexego Sistemas Informáticos All Rights Reserved
#    $<NAME>$ <<EMAIL>>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import models, fields, api, _
import time
from datetime import datetime


class PerformanceCalculation(models.TransientModel):
    _name = 'performance.calculation'

    name = fields.Char('Name', size=255, required=True)
    report_type = fields.Selection([
        ('oee', 'OEE'),
        ('scrap_and_usage', 'Scrap & Usage'),
        ('overweight', 'Overweight'),
        ], string='Report type', required=True)
    between_dates = fields.Boolean('Between dates')
    date_start = fields.Date('Date start')
    date_stop = fields.Date('Date stop')
    by_routing = fields.Boolean('By routing')
    routing_id = fields.Many2one('mrp.routing', 'Routing')
    by_product = fields.Boolean('By product')
    product_id = fields.Many2one('product.product', 'Product')
    by_workcenter = fields.Boolean('By workcenter')
    workcenter_id = fields.Many2one('mrp.workcenter', 'Workcenter')

    @api.multi
    def _get_moves_by_filters(self):
        self.ensure_one()
        domain = [
            ('production_state', '=', 'done'),
            ('production_type', '=', 'normal')
        ]
        if self.between_dates and self.date_start and self.date_stop:
            domain.append(('date_start', '>=', self.date_start))
            domain.append(('date_start', '<=', self.date_stop))
            domain.append(('date_finished', '<=', self.date_stop))
            domain.append(('date_finished', '>=', self.date_start))
        if self.by_routing and self.routing_id:
            domain.append(('routing_id', '=', self.routing_id.id))
        if self.by_product and self.product_id:
            domain.append(('product', '=', self.product_id.id))
        if self.by_workcenter and self.workcenter_id:
            domain.append(('workcenter_id', '=', self.workcenter_id.id))
        result = self.env['mrp.production.workcenter.line'].search(domain)
        return result

    @api.multi
    def _get_name_by_filters(self):
        self.ensure_one()
        report_name_comp = ''
        if self.between_dates and self.date_start and self.date_stop:
            report_name_comp += _(" From: ") + self.date_start + _(" to: ") + self.date_stop
        if self.by_routing and self.routing_id:
            report_name_comp += _(" Routing: ") + self.routing_id.name
        if self.by_product and self.product_id:
            report_name_comp += _(" Product: ") + self.product_id.name
        if self.by_workcenter and self.workcenter_id:
            report_name_comp += _(" Workcenter: ") + self.workcenter_id.name
        return report_name_comp

    @api.model
    def _get_total_stop_time(self, wl):
        stop_time = 0.0
        minimum_time = 2.0 / 60.0 # 2 minutos (las iguales o inferiores a este tiempo no se computan)
        production_stops_ids = wl.production_stops_ids.filtered(
            lambda r: r.in_production and r.time > minimum_time)
        for stop in production_stops_ids:
            stop_time += stop.time
        return stop_time

    @api.model
    def _get_total_qty(self, production):
        qty_finished = 0.0
        qty_real_finished = 0.0
        qty_scrap = 0.0
        for move in production.move_created_ids2:
            if move.state != 'done':
                continue
            scrapped_move = move.location_dest_id.scrap_location
            if not scrapped_move or (scrapped_move and move.location_id.usage == 'production'):
                qty_finished += move.product_uom_qty
            if scrapped_move:
                qty_scrap += move.product_uom_qty
            if not scrapped_move:
                qty_real_finished += move.product_uom_qty
            elif move.location_id.usage == 'internal':
                qty_real_finished -= move.product_uom_qty
        return qty_finished, qty_real_finished, qty_scrap

    @api.model
    def _get_availability(self, times_for_availability=0.0, estimated_time=0.0, time_cycle=0.0, qty_per_cycle=0.0, factor=0.0):
        a = time_cycle / (qty_per_cycle or 1.0)
        b = (a * factor) + times_for_availability
        return (estimated_time / (b or 1.0 ))

    @api.model
    def _get_performance(self, estimated_time=0.0, times_for_performance=0.0):
        return (estimated_time / (times_for_performance or 1.0))

    @api.model
    def _get_quality(self, qty_finished=0.0, qty_scrap=0.0):
        return ((qty_finished - qty_scrap) / (qty_finished or 1.0))

    @api.model
    def _get_oee(self, wl=False):
        # OEE = (Availability * Efficiency * Quality) * 100
        wc_obj = self.env['mrp.routing.workcenter']
        uom_obj = self.env['product.uom']
        a = p = q = 0.0
        if wl:
            stop_time = self._get_total_stop_time(wl)
            times_for_availability = stop_time + wl.time_start + wl.time_stop
            times_for_performance = wl.real_time - stop_time
            qty_finished, qty_real_finished, qty_scrap = self._get_total_qty(wl.production_id)
            name_routing_workcenter = ((wl.name).split('-')[0])[:-1]
            domain = [
                ('routing_id', '=', wl.routing_id.id),
                ('name', 'like', name_routing_workcenter)
            ]
            routing_id = wc_obj.search(domain, limit=1)
            if routing_id:
                factor = qty_finished
                qty_per_cycle = uom_obj._compute_qty(
                    routing_id.uom_id.id,
                    routing_id.qty_per_cycle,
                    wl.production_id.bom_id.product_uom.id)
                estimated_time = float((routing_id.hour_nbr / (qty_per_cycle or 1.0)) * factor)
                time_cycle = routing_id.hour_nbr
                a = self._get_availability(times_for_availability, estimated_time, time_cycle, qty_per_cycle, factor)
                p = self._get_performance(estimated_time, times_for_performance)
                q = self._get_quality(qty_finished, qty_scrap)
        oee = (a * p * q) * 100
        return (a*100), (p*100), (q*100), oee

    @api.model
    def _get_scrap_and_usage(self, prod=False):
        qty_finished = real_qty_finished = qty_scrap =0.0
        theo_cost = real_real_cost = 0.0
        scrap = usage = 0.0
        if prod:
            qty_finished = self._calc_finished_qty(prod)
            real_qty_finished = self._calc_real_finished_qty(prod)
            qty_scrap = qty_finished - real_qty_finished
            theo_cost = self._get_theo_cost(prod, qty_finished)
            real_cost = self._get_real_cost(prod)
            scrap = qty_scrap * (theo_cost / qty_finished)
            for move in prod.move_lines2:
                if move.state != 'done':
                    continue
                scrapped_move = move.location_dest_id.scrap_location
                if scrapped_move:
                    scrap += (move.price_unit * move.product_uom_qty)
            usage = real_cost - theo_cost
            real_real_cost = real_cost + scrap
        res = {
           'qty_finished': qty_finished,<commit_msg>Evitamos división por cero cuando cantidad finalizada es nula<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2004-2012 Pexego Sistemas Informáticos All Rights Reserved
#    $<NAME>$ <<EMAIL>>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import models, fields, api, _
import time
from datetime import datetime


class PerformanceCalculation(models.TransientModel):
    _name = 'performance.calculation'

    name = fields.Char('Name', size=255, required=True)
    report_type = fields.Selection([
        ('oee', 'OEE'),
        ('scrap_and_usage', 'Scrap & Usage'),
        ('overweight', 'Overweight'),
        ], string='Report type', required=True)
    between_dates = fields.Boolean('Between dates')
    date_start = fields.Date('Date start')
    date_stop = fields.Date('Date stop')
    by_routing = fields.Boolean('By routing')
    routing_id = fields.Many2one('mrp.routing', 'Routing')
    by_product = fields.Boolean('By product')
    product_id = fields.Many2one('product.product', 'Product')
    by_workcenter = fields.Boolean('By workcenter')
    workcenter_id = fields.Many2one('mrp.workcenter', 'Workcenter')

    @api.multi
    def _get_moves_by_filters(self):
        self.ensure_one()
        domain = [
            ('production_state', '=', 'done'),
            ('production_type', '=', 'normal')
        ]
        if self.between_dates and self.date_start and self.date_stop:
            domain.append(('date_start', '>=', self.date_start))
            domain.append(('date_start', '<=', self.date_stop))
            domain.append(('date_finished', '<=', self.date_stop))
            domain.append(('date_finished', '>=', self.date_start))
        if self.by_routing and self.routing_id:
            domain.append(('routing_id', '=', self.routing_id.id))
        if self.by_product and self.product_id:
            domain.append(('product', '=', self.product_id.id))
        if self.by_workcenter and self.workcenter_id:
            domain.append(('workcenter_id', '=', self.workcenter_id.id))
        result = self.env['mrp.production.workcenter.line'].search(domain)
        return result

    @api.multi
    def _get_name_by_filters(self):
        self.ensure_one()
        report_name_comp = ''
        if self.between_dates and self.date_start and self.date_stop:
            report_name_comp += _(" From: ") + self.date_start + _(" to: ") + self.date_stop
        if self.by_routing and self.routing_id:
            report_name_comp += _(" Routing: ") + self.routing_id.name
        if self.by_product and self.product_id:
            report_name_comp += _(" Product: ") + self.product_id.name
        if self.by_workcenter and self.workcenter_id:
            report_name_comp += _(" Workcenter: ") + self.workcenter_id.name
        return report_name_comp

    @api.model
    def _get_total_stop_time(self, wl):
        stop_time = 0.0
        minimum_time = 2.0 / 60.0 # 2 minutos (las iguales o inferiores a este tiempo no se computan)
        production_stops_ids = wl.production_stops_ids.filtered(
            lambda r: r.in_production and r.time > minimum_time)
        for stop in production_stops_ids:
            stop_time += stop.time
        return stop_time

    @api.model
    def _get_total_qty(self, production):
        qty_finished = 0.0
        qty_real_finished = 0.0
        qty_scrap = 0.0
        for move in production.move_created_ids2:
            if move.state != 'done':
                continue
            scrapped_move = move.location_dest_id.scrap_location
            if not scrapped_move or (scrapped_move and move.location_id.usage == 'production'):
                qty_finished += move.product_uom_qty
            if scrapped_move:
                qty_scrap += move.product_uom_qty
            if not scrapped_move:
                qty_real_finished += move.product_uom_qty
            elif move.location_id.usage == 'internal':
                qty_real_finished -= move.product_uom_qty
        return qty_finished, qty_real_finished, qty_scrap

    @api.model
    def _get_availability(self, times_for_availability=0.0, estimated_time=0.0, time_cycle=0.0, qty_per_cycle=0.0, factor=0.0):
        a = time_cycle / (qty_per_cycle or 1.0)
        b = (a * factor) + times_for_availability
        return (estimated_time / (b or 1.0 ))

    @api.model
    def _get_performance(self, estimated_time=0.0, times_for_performance=0.0):
        return (estimated_time / (times_for_performance or 1.0))

    @api.model
    def _get_quality(self, qty_finished=0.0, qty_scrap=0.0):
        return ((qty_finished - qty_scrap) / (qty_finished or 1.0))

    @api.model
    def _get_oee(self, wl=False):
        # OEE = (Availability * Efficiency * Quality) * 100
        wc_obj = self.env['mrp.routing.workcenter']
        uom_obj = self.env['product.uom']
        a = p = q = 0.0
        if wl:
            stop_time = self._get_total_stop_time(wl)
            times_for_availability = stop_time + wl.time_start + wl.time_stop
            times_for_performance = wl.real_time - stop_time
            qty_finished, qty_real_finished, qty_scrap = self._get_total_qty(wl.production_id)
            name_routing_workcenter = ((wl.name).split('-')[0])[:-1]
            domain = [
                ('routing_id', '=', wl.routing_id.id),
                ('name', 'like', name_routing_workcenter)
            ]
            routing_id = wc_obj.search(domain, limit=1)
            if routing_id:
                factor = qty_finished
                qty_per_cycle = uom_obj._compute_qty(
                    routing_id.uom_id.id,
                    routing_id.qty_per_cycle,
                    wl.production_id.bom_id.product_uom.id)
                estimated_time = float((routing_id.hour_nbr / (qty_per_cycle or 1.0)) * factor)
                time_cycle = routing_id.hour_nbr
                a = self._get_availability(times_for_availability, estimated_time, time_cycle, qty_per_cycle, factor)
                p = self._get_performance(estimated_time, times_for_performance)
                q = self._get_quality(qty_finished, qty_scrap)
        oee = (a * p * q) * 100
        return (a*100), (p*100), (q*100), oee

    @api.model
    def _get_scrap_and_usage(self, prod=False):
        qty_finished = real_qty_finished = qty_scrap = 0.0
        theo_cost = real_real_cost = 0.0
        scrap = usage = 0.0
        if prod:
            qty_finished = self._calc_finished_qty(prod)
            real_qty_finished = self._calc_real_finished_qty(prod)
            qty_scrap = qty_finished - real_qty_finished
            theo_cost = self._get_theo_cost(prod, qty_finished)
            real_cost = self._get_real_cost(prod)
            scrap = qty_scrap * (theo_cost / (qty_finished or 1.0))
            for move in prod.move_lines2:
                if move.state != 'done':
                    continue
                scrapped_move = move.location_dest_id.scrap_location
                if scrapped_move:
                    scrap += (move.price_unit * move.product_uom_qty)
            usage = real_cost - theo_cost
            real_real_cost = real_cost + scrap
        res = {
           'qty_finished': qty_finished,
{'fraction_non_alphanumeric': 0.1211035696329814, 'fraction_numerical': 0.010935143288084464, 'mean_word_length': 2.4965941551307407, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4150782', 'n_tokens_mistral': 5099, 'n_tokens_neox': 4931, 'n_words': 1059}