<commit_before># -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

import warnings
from decimal import Decimal

from django.utils.encoding import force_text

from shoop.core.models import Order, OrderLine, OrderLineType
from shoop.core.order_creator.signals import order_creator_finished
from shoop.core.shortcuts import update_order_line_from_product
from shoop.core.utils.users import real_user_or_none
from shoop.utils.numbers import bankers_round

from ._source_modifier import get_order_source_modifier_modules


class OrderProcessor(object):

    def source_line_to_order_lines(self, order, source_line):
        """
        Convert a SourceLine into one or more OrderLines (yield them)
        :param order: The order
        :param source_line: The SourceLine
        """
        order_line = OrderLine(order=order)
        product = source_line.product
        quantity = Decimal(source_line.quantity)
        if product:
            order_line.product = product
            if product.sales_unit:
                quantized_quantity = bankers_round(quantity, product.sales_unit.decimals)
                if quantized_quantity != quantity:
                    raise ValueError("Sales unit decimal conversion causes precision loss!")
        else:
            order_line.product = None

        def text(value):
            return force_text(value) if value is not None else ""

        order_line.quantity = quantity
        order_line.supplier = source_line.supplier
        order_line.sku = text(source_line.sku)
        order_line.text = (text(source_line.text))[:192]
        if source_line.base_unit_price:
            order_line.base_unit_price = source_line.base_unit_price
        if source_line.discount_amount:
            order_line.discount_amount = source_line.discount_amount
        order_line.type = (source_line.type if source_line.type is not None
                           else OrderLineType.OTHER)
        order_line.accounting_identifier = text(source_line.accounting_identifier)
        order_line.require_verification = bool(source_line.require_verification)
        order_line.verified = (not order_line.require_verification)
        order_line.source_line = source_line
        order_line.parent_source_line = source_line.parent_line
        self._check_orderability(order_line)

        yield order_line

        for child_order_line in self.create_package_children(order_line):
            yield child_order_line

    def create_package_children(self, order_line):
        order = order_line.order
        parent_product = order_line.product
        # :type parent_product: shoop.core.models.Product
        if not (parent_product and parent_product.is_package_parent()):
            return

        for child_product, child_quantity in six.iteritems(parent_product.get_package_child_to_quantity_map()):
            child_order_line = OrderLine(order=order, parent_line=order_line)
            update_order_line_from_product(
                pricing_context=None,
                order_line=child_order_line,
                product=child_product,
                quantity=(order_line.quantity * child_quantity),
            )
            # Package children are free
            assert child_order_line.base_unit_price.value == 0
            child_order_line.source_line = None
            child_order_line.parent_source_line = order_line.source_line
            child_order_line.supplier = order_line.supplier
            self._check_orderability(child_order_line)
            yield child_order_line

    def _check_orderability(self, order_line):
        if not order_line.product:
            return
        if not order_line.supplier:
            raise ValueError("Order line has no supplier")
        order = order_line.order
        shop_product = order_line.product.get_shop_instance(order.shop)
        shop_product.raise_if_not_orderable(
            supplier=order_line.supplier,
            quantity=order_line.quantity,
            customer=order.customer
        )

    def process_saved_order_line(self, order, order_line):
        """
        Called in sequence for all order lines to be saved into the order. These have all been saved, so they have PKs.
        :type order: Order
        :type order_line: OrderLine
        """
        pass

    def add_lines_into_order(self, order, lines):
        # Map source lines to order lines for parentage linking
        order_line_by_source = {
            id(order_line.source_line): order_line
            for order_line in lines
        }

        # Set line ordering, parentage and save the lines
        for index, order_line in enumerate(lines):
            order_line.order = order
            order_line.ordering = index

            parent_src_line = order_line.parent_source_line
            if parent_src_line:
                parent_order_line = order_line_by_source[id(parent_src_line)]
                assert parent_order_line.pk, "Parent line should be saved"
                order_line.parent_line = parent_order_line

            order_line.save()

        self.add_line_taxes(lines)

        # And one last pass to call the subclass hook.
        for order_line in lines:
            self.process_saved_order_line(order=order, order_line=order_line)

    def add_line_taxes(self, lines):
        for line in lines:
            if not line.source_line:
                continue  # Cannot have taxes, since not in source
            for (index, line_tax) in enumerate(line.source_line.taxes, 1):
                line.taxes.create(
                    tax=line_tax.tax,
                    name=line_tax.name,
                    amount_value=line_tax.amount.value,
                    base_amount_value=line_tax.base_amount.value,
                    ordering=index,
                )

    def get_source_order_lines(self, source, order):
        """
        :type source: shoop.core.order_creator.OrderSource
        :type order: shoop.core.models.Order
        """
        lines = []
        source.update_from_order(order)
        # Since we just updated `order_provision`, we need to uncache
        # the processed lines.
        source.uncache()
        for line in source.get_final_lines(with_taxes=True):
            lines.extend(self.source_line_to_order_lines(order, line))<commit_msg>OrderCreator: Doc and comment clean-up<commit_after># -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

import warnings
from decimal import Decimal

from django.utils.encoding import force_text

from shoop.core.models import Order, OrderLine, OrderLineType
from shoop.core.order_creator.signals import order_creator_finished
from shoop.core.shortcuts import update_order_line_from_product
from shoop.core.utils.users import real_user_or_none
from shoop.utils.numbers import bankers_round

from ._source_modifier import get_order_source_modifier_modules


class OrderProcessor(object):

    def source_line_to_order_lines(self, order, source_line):
        """
        Convert a source line into one or more order lines.

        Normally each source line will yield just one order line, but
        package products will yield a parent line and its child lines.

        :type order: shoop.core.models.Order
        :param order: The order
        :type source_line: shoop.core.order_creator.SourceLine
        :param source_line: The SourceLine
        :rtype: Iterable[OrderLine]
        """
        order_line = OrderLine(order=order)
        product = source_line.product
        quantity = Decimal(source_line.quantity)
        if product:
            order_line.product = product
            if product.sales_unit:
                quantized_quantity = bankers_round(quantity, product.sales_unit.decimals)
                if quantized_quantity != quantity:
                    raise ValueError("Sales unit decimal conversion causes precision loss!")
        else:
            order_line.product = None

        def text(value):
            return force_text(value) if value is not None else ""

        order_line.quantity = quantity
        order_line.supplier = source_line.supplier
        order_line.sku = text(source_line.sku)
        order_line.text = (text(source_line.text))[:192]
        if source_line.base_unit_price:
            order_line.base_unit_price = source_line.base_unit_price
        if source_line.discount_amount:
            order_line.discount_amount = source_line.discount_amount
        order_line.type = (source_line.type if source_line.type is not None
                           else OrderLineType.OTHER)
        order_line.accounting_identifier = text(source_line.accounting_identifier)
        order_line.require_verification = bool(source_line.require_verification)
        order_line.verified = (not order_line.require_verification)
        order_line.source_line = source_line
        order_line.parent_source_line = source_line.parent_line
        self._check_orderability(order_line)

        yield order_line

        for child_order_line in self.create_package_children(order_line):
            yield child_order_line

    def create_package_children(self, order_line):
        order = order_line.order
        parent_product = order_line.product
        # :type parent_product: shoop.core.models.Product
        if not (parent_product and parent_product.is_package_parent()):
            return

        child_to_quantity = parent_product.get_package_child_to_quantity_map()
        for (child_product, child_quantity) in child_to_quantity.items():
            child_order_line = OrderLine(order=order, parent_line=order_line)
            update_order_line_from_product(
                pricing_context=None,  # Will use zero price
                order_line=child_order_line,
                product=child_product,
                quantity=(order_line.quantity * child_quantity),
            )
            # Package children are free
            assert child_order_line.base_unit_price.value == 0
            child_order_line.source_line = None
            child_order_line.parent_source_line = order_line.source_line
            child_order_line.supplier = order_line.supplier
            self._check_orderability(child_order_line)
            yield child_order_line

    def _check_orderability(self, order_line):
        if not order_line.product:
            return
        if not order_line.supplier:
            raise ValueError("Order line has no supplier")
        order = order_line.order
        shop_product = order_line.product.get_shop_instance(order.shop)
        shop_product.raise_if_not_orderable(
            supplier=order_line.supplier,
            quantity=order_line.quantity,
            customer=order.customer
        )

    def process_saved_order_line(self, order, order_line):
        """
        Called in sequence for all order lines to be saved into the order. These have all been saved, so they have PKs.
        :type order: Order
        :type order_line: OrderLine
        """
        pass

    def add_lines_into_order(self, order, lines):
        # Map source lines to order lines for parentage linking
        order_line_by_source = {
            id(order_line.source_line): order_line
            for order_line in lines
        }

        # Set line ordering, parentage and save the lines
        for index, order_line in enumerate(lines):
            order_line.order = order
            order_line.ordering = index

            parent_src_line = order_line.parent_source_line
            if parent_src_line:
                parent_order_line = order_line_by_source[id(parent_src_line)]
                assert parent_order_line.pk, "Parent line should be saved"
                order_line.parent_line = parent_order_line

            order_line.save()

        self.add_line_taxes(lines)

        # And one last pass to call the subclass hook.
        for order_line in lines:
            self.process_saved_order_line(order=order, order_line=order_line)

    def add_line_taxes(self, lines):
        for line in lines:
            if not line.source_line:
                continue  # Cannot have taxes, since not in source
            for (index, line_tax) in enumerate(line.source_line.taxes, 1):
                line.taxes.create(
                    tax=line_tax.tax,
                    name=line_tax.name,
                    amount_value=line_tax.amount.value,
                    base_amount_value=line_tax.base_amount.value,
                    ordering=index,
                )

    def get_source_order_lines(self, source, order):
        """
        :type source: shoop.core.order_creator.OrderSource
        :type order: shoop.core.models.Order
        :rtype: list[OrderLine]
        """
        lines = []
        source.update_from_order(order)
        # Since we just updated `order_provision`, we need to uncache
        # the processed lines.
        source.uncache()
        for line in source.get_final_lines(with_taxes=True):
            lines.extend(self.source_line_to_order_lines(order, line))
{'fraction_non_alphanumeric': 0.06372403560830861, 'fraction_numerical': 0.002225519287833828, 'mean_word_length': 2.4434227330779055, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '2871261', 'n_tokens_mistral': 3792, 'n_tokens_neox': 3648, 'n_words': 883}