def close_order_delivery(permanence, delivery, all_producers, producers_id=None): from repanier.apps import REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS getcontext().rounding = ROUND_HALF_UP if REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS: # Cancel unconfirmed purchases whichever the producer is customer_invoice_qs = CustomerInvoice.objects.filter( permanence_id=permanence.id, delivery=delivery, is_order_confirm_send=False, total_price_with_tax__gt=DECIMAL_ZERO, ) for customer_invoice in customer_invoice_qs: customer_invoice.delete_if_unconfirmed(permanence) if all_producers: # 1 - Do not round to multiple producer_order_by_quantity # 2 - Do not add Transport for customer in Customer.objects.filter( is_active=True, may_order=True, customerinvoice__permanence_id=permanence.id, customerinvoice__delivery=delivery, customerinvoice__total_price_with_tax__gt=DECIMAL_ZERO, represent_this_buyinggroup=False).order_by('?'): # 3 - Add Deposit for offer_item in OfferItem.objects.filter( permanence_id=permanence.id, order_unit=PRODUCT_ORDER_UNIT_DEPOSIT).order_by('?'): create_or_update_one_purchase( customer.id, offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False) create_or_update_one_purchase( customer.id, offer_item, q_order=0, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False) delivery.set_status(PERMANENCE_CLOSED, all_producers, producers_id)
def import_invoice_sheet(worksheet, invoice_reference=EMPTY_STRING, customer_2_id_dict=None, producer=None ): error = False error_msg = None header = get_header(worksheet) if header: now = timezone.now().date() lut_reverse_vat = dict(LUT_ALL_VAT_REVERSE) import_counter = 0 row_num = 1 sid = transaction.savepoint() try: permanence = Permanence.objects.create( permanence_date=now, short_name=invoice_reference, status=PERMANENCE_SEND, highest_status=PERMANENCE_SEND ) permanence.producers.add(producer) row = get_row(worksheet, header, row_num) while row and not error: customer_name = row[_("Customer")] if customer_name: if customer_name in customer_2_id_dict: customer_id = customer_2_id_dict[customer_name] else: error = True error_msg = _("Row %(row_num)d : No valid customer") % {'row_num': row_num + 1} break product_reference = row[_("Reference")] or EMPTY_STRING unit = row[_("Unit")] order_unit = get_reverse_invoice_unit(unit) vat = row[_("VAT level")] vat_level = lut_reverse_vat[vat] product = Product.objects.filter(producer_id=producer.id, reference=product_reference).order_by( '?').first() if product is None: product = Product.objects.create( producer=producer, reference=product_reference, ) long_name = row[_("Product")] # The producer unit price is the imported customer unit price # If the group get a reduction, this one must be mentioned into the producer admin screen # into the "price_list_multiplier" field product.producer_unit_price = row[_("Customer unit price")] product.unit_deposit = row[_("Deposit")] product.order_unit = order_unit product.vat_level = vat_level product.wrapped = row[_("Wrapped")] qty_and_price_display = product.get_qty_and_price_display(customer_price=False) if long_name.endswith(qty_and_price_display): long_name = long_name[:-len(qty_and_price_display)] product.long_name = long_name[:100] product.save() offer_item = product.get_or_create_offer_item(permanence) create_or_update_one_purchase( customer_id=customer_id, offer_item=offer_item, status=PERMANENCE_SEND, q_order=Decimal(row[_("Quantity")]), batch_job=True, is_box_content=False, comment=row[_("Comment")] or EMPTY_STRING ) import_counter += 1 row_num += 1 row = get_row(worksheet, header, row_num) reorder_offer_items(permanence.id) reorder_purchases(permanence.id) except KeyError as e: # Missing field error = True error_msg = _("Row %(row_num)d : A required column is missing %(error_msg)s.") % { 'row_num': row_num + 1, 'error_msg': str(e)} except Exception as e: error = True error_msg = _("Row %(row_num)d : %(error_msg)s.") % {'row_num': row_num + 1, 'error_msg': str(e)} if not error and import_counter == 0: error = True error_msg = "{}".format(_("Nothing to import.")) if error: transaction.savepoint_rollback(sid) else: transaction.savepoint_commit(sid) return error, error_msg
def import_invoice_sheet(worksheet, invoice_reference=EMPTY_STRING, customer_2_id_dict=None, producer=None ): error = False error_msg = None header = get_header(worksheet) if header: now = timezone.now().date() lut_reverse_vat = dict(LUT_ALL_VAT_REVERSE) import_counter = 0 row_num = 1 sid = transaction.savepoint() try: permanence = Permanence.objects.create( permanence_date=now, short_name=invoice_reference, status=PERMANENCE_SEND, highest_status=PERMANENCE_SEND ) permanence.producers.add(producer) row = get_row(worksheet, header, row_num) while row and not error: customer_name = row[_("Customer")] if customer_name: if customer_name in customer_2_id_dict: customer_id = customer_2_id_dict[customer_name] else: error = True error_msg = _("Row %(row_num)d : No valid customer") % {'row_num': row_num + 1} break product_reference = row[_("Reference")] or EMPTY_STRING unit = row[_("Unit")] order_unit = get_reverse_invoice_unit(unit) vat = row[_("VAT level")] vat_level = lut_reverse_vat[vat] product = Product.objects.filter(producer_id=producer.id, reference=product_reference).order_by( '?').first() if product is None: product = Product.objects.create( producer=producer, reference=product_reference, ) long_name = row[_("Product")] # The producer unit price is the imported customer unit price # If the group get a reduction, this one must be mentioned into the producer admin screen # into the "price_list_multiplier" field product.producer_unit_price = row[_("Customer unit price")] product.unit_deposit = row[_("Deposit")] product.order_unit = order_unit product.vat_level = vat_level product.wrapped = row[_("Wrapped")] qty_and_price_display = product.get_qty_and_price_display(customer_price=False) if long_name.endswith(qty_and_price_display): long_name = long_name[:-len(qty_and_price_display)] product.long_name = long_name[:100] product.save() offer_item = product.get_or_create_offer_item(permanence, reset_add_2_stock=True) create_or_update_one_purchase( customer_id=customer_id, offer_item=offer_item, status=PERMANENCE_SEND, q_order=Decimal(row[_("Quantity")]), batch_job=True, is_box_content=False, comment=row[_("Comment")] or EMPTY_STRING ) import_counter += 1 row_num += 1 row = get_row(worksheet, header, row_num) reorder_offer_items(permanence.id) reorder_purchases(permanence.id) except KeyError as e: # Missing field error = True error_msg = _("Row %(row_num)d : A required column is missing %(error_msg)s.") % { 'row_num': row_num + 1, 'error_msg': str(e)} except Exception as e: error = True error_msg = _("Row %(row_num)d : %(error_msg)s.") % {'row_num': row_num + 1, 'error_msg': str(e)} if not error and import_counter == 0: error = True error_msg = "{}".format(_("Nothing to import.")) if error: transaction.savepoint_rollback(sid) else: transaction.savepoint_commit(sid) return error, error_msg
def close_order(permanence, all_producers, producers_id=None): getcontext().rounding = ROUND_HALF_UP today = timezone.now().date() if repanier.apps.REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS: # 0 - Cancel unconfirmed purchases purchase_qs = Purchase.objects.filter( permanence_id=permanence.id, customer_invoice__is_order_confirm_send=False, is_box_content=False ).exclude( quantity_ordered=DECIMAL_ZERO ).order_by('customer_invoice') if not all_producers: purchase_qs = purchase_qs.filter(producer_id__in=producers_id) customer_invoice_id_save = -1 for purchase in purchase_qs.select_related("customer", "offer_item"): if customer_invoice_id_save != purchase.customer_invoice_id: customer_invoice_id_save = purchase.customer_invoice_id # This order has been cancelled # filename = force_filename("%s - %s.xlsx" % (_("Canceled order"), permanence)) filename = "{0}-{1}.xlsx".format( slugify(_("Canceled order")), slugify(permanence) ) sender_email, sender_function, signature, cc_email_staff = get_signature( is_reply_to_order_email=True) export_order_2_1_customer( purchase.customer, filename, permanence, sender_email, sender_function, signature, cancel_order=True) update_or_create_purchase( customer=purchase.customer, offer_item_id=purchase.offer_item.id, value_id=DECIMAL_ZERO, batch_job=True ) else: # 0 - Delete unused purchases purchase_qs = Purchase.objects.filter( permanence_id=permanence.id, quantity_ordered=0 ).order_by('?') if not all_producers: purchase_qs = purchase_qs.filter(producer_id__in=producers_id) purchase_qs.delete() # 1 - Round to multiple producer_order_by_quantity offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, is_active=True, order_unit__lt=PRODUCT_ORDER_UNIT_DEPOSIT, producer_order_by_quantity__gt=1, quantity_invoiced__gt=0 ).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: # It's possible to round the ordered qty even If we do not manage stock if offer_item.manage_replenishment: needed = (offer_item.quantity_invoiced - offer_item.stock) else: needed = offer_item.quantity_invoiced if needed > DECIMAL_ZERO: offer_item.add_2_stock = offer_item.producer_order_by_quantity - ( needed % offer_item.producer_order_by_quantity) offer_item.save() # 2 - Add Transport offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, is_active=False, order_unit=PRODUCT_ORDER_UNIT_TRANSPORTATION ).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: buying_group = Customer.objects.filter(is_active=True, represent_this_buyinggroup=True).order_by('?').first() create_or_update_one_purchase(buying_group, offer_item, 1, None, True, is_box_content=False) membership_fee_product = Product.objects.filter(is_membership_fee=True, is_active=True).order_by('?').first() membership_fee_product.producer_unit_price = repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE # Update the prices membership_fee_product.save() membership_fee_offer_item = get_or_create_offer_item( permanence, membership_fee_product.id, membership_fee_product.producer_id ) for customer in Customer.objects.filter( is_active=True, may_order=True, customerinvoice__permanence_id=permanence.id, customerinvoice__total_price_with_tax__gt=DECIMAL_ZERO, represent_this_buyinggroup=False ).order_by('?'): # 3 - Add Deposit offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, order_unit=PRODUCT_ORDER_UNIT_DEPOSIT ).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: create_or_update_one_purchase(customer, offer_item, 1, None, True, is_box_content=False) create_or_update_one_purchase(customer, offer_item, 0, None, True, is_box_content=False) # 4 - Add Add Membership fee Subscription if repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION > 0: # There is a membership fee if customer.membership_fee_valid_until < today: permanence.producers.add(membership_fee_offer_item.producer_id) create_or_update_one_purchase(customer, membership_fee_offer_item, 1, None, True, is_box_content=False) while customer.membership_fee_valid_until < today: # Do not pay the membership fee if no order passed during a certain amount of time customer.membership_fee_valid_until = add_months( customer.membership_fee_valid_until, repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION ) customer.save(update_fields=['membership_fee_valid_until', ]) # 5 - Add Common participation Subscription if all_producers: for offer_item in OfferItem.objects.filter( permanence_id=permanence.id, is_membership_fee=False, order_unit=PRODUCT_ORDER_UNIT_SUBSCRIPTION ).order_by('?'): for customer in Customer.objects.filter( is_active=True, may_order=True, represent_this_buyinggroup=False ).order_by('?'): permanence.producers.add(offer_item.producer_id) create_or_update_one_purchase(customer, offer_item, 1, None, True, is_box_content=False) # Disable subscription for next permanence Product.objects.filter( order_unit=PRODUCT_ORDER_UNIT_SUBSCRIPTION, is_into_offer=True, is_membership_fee=False ).order_by('?').update(is_into_offer=False) permanence.set_status(PERMANENCE_CLOSED, allow_downgrade=False) if not repanier.apps.REPANIER_SETTINGS_INVOICE and repanier.apps.REPANIER_SETTINGS_BANK_ACCOUNT is None: # No Invoice and no bank_account --> auto archive # Put send permanences to the done status, because they will "never" be invoiced for permanence in Permanence.objects.filter(status=PERMANENCE_SEND): permanence.set_status(PERMANENCE_ARCHIVED, update_payment_date=True) else: permanence.set_status(PERMANENCE_CLOSED, all_producers=all_producers, producers_id=producers_id) # 6 - Refresh the Purchase 'sum' for each customer recalculate_order_amount( permanence_id=permanence.id, all_producers=all_producers, producers_id=producers_id, send_to_producer=False, )
def close_order_delivery(permanence, delivery, all_producers, producers_id=None): today = timezone.now().date() getcontext().rounding = ROUND_HALF_UP # 0 - Delete unused purchases # No need to select : customer_invoice__delivery = delivery Purchase.objects.filter( permanence_id=permanence.id, quantity_ordered=0 ).order_by('?').delete() if repanier.apps.REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS: purchase_qs = Purchase.objects.filter( permanence_id=permanence.id, customer_invoice__delivery=delivery, customer_invoice__is_order_confirm_send=False, is_box_content=False ).exclude( quantity_ordered=DECIMAL_ZERO ).order_by('customer_invoice') if not all_producers: # This may never be the but, but... purchase_qs = purchase_qs.filter(producer_id__in=producers_id) customer_invoice_id_save = -1 for purchase in purchase_qs.select_related("customer", "offer_item"): if customer_invoice_id_save != purchase.customer_invoice_id: customer_invoice_id_save =purchase.customer_invoice_id # This order has been cancelled # filename = force_filename("%s - %s.xlsx" % (_("Canceled order"), permanence)) filename = "{0}-{1}.xlsx".format( slugify(_("Canceled order")), slugify(permanence) ) sender_email, sender_function, signature, cc_email_staff = get_signature( is_reply_to_order_email=True) export_order_2_1_customer( purchase.customer, filename, permanence, sender_email, sender_function, signature, cancel_order=True) update_or_create_purchase( customer=purchase.customer, offer_item_id=purchase.offer_item.id, value_id=DECIMAL_ZERO, batch_job=True ) if all_producers: # 1 - Do not round to multiple producer_order_by_quantity # 2 - Do not add Transport membership_fee_product = Product.objects.filter(is_membership_fee=True, is_active=True).order_by('?').first() membership_fee_product.producer_unit_price = repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE # Update the prices membership_fee_product.save() membership_fee_offer_item = get_or_create_offer_item(permanence, membership_fee_product.id, membership_fee_product.producer_id) for customer in Customer.objects.filter( is_active=True, may_order=True, customerinvoice__permanence_id=permanence.id, customerinvoice__delivery=delivery, customerinvoice__total_price_with_tax__gt=DECIMAL_ZERO, represent_this_buyinggroup=False ).order_by('?'): # 3 - Add Deposit for offer_item in OfferItem.objects.filter(permanence_id=permanence.id, # is_active=False, order_unit=PRODUCT_ORDER_UNIT_DEPOSIT).order_by('?'): permanence.producers.add(offer_item.producer_id) create_or_update_one_purchase(customer, offer_item, 1, None, True, is_box_content=False) create_or_update_one_purchase(customer, offer_item, 0, None, True, is_box_content=False) # 4 - Add Membership fee Subscription if repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION > 0: # There is a membership fee if customer.membership_fee_valid_until < today: permanence.producers.add(membership_fee_offer_item.producer_id) create_or_update_one_purchase(customer, membership_fee_offer_item, 1, None, True, is_box_content=False) customer.membership_fee_valid_until = add_months( customer.membership_fee_valid_until, repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION ) customer.save(update_fields=['membership_fee_valid_until', ]) # 5 - Add Common participation Subscription for offer_item in OfferItem.objects.filter( permanence_id=permanence.id, is_membership_fee=False, order_unit=PRODUCT_ORDER_UNIT_SUBSCRIPTION).order_by('?'): for customer in Customer.objects.filter(is_active=True, may_order=True, represent_this_buyinggroup=False).order_by('?'): permanence.producers.add(offer_item.producer_id) create_or_update_one_purchase(customer, offer_item, 1, None, True, is_box_content=False) # 6 - Refresh the Purchase 'sum' recalculate_order_amount( permanence_id=permanence.id, all_producers=all_producers, producers_id=producers_id, send_to_producer=False ) delivery.set_status(PERMANENCE_CLOSED, all_producers, producers_id)
def close_order(permanence, all_producers, producers_id=None): from repanier.apps import REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS getcontext().rounding = ROUND_HALF_UP if REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS: # Cancel unconfirmed purchases whichever the producer is customer_invoice_qs = CustomerInvoice.objects.filter( permanence_id=permanence.id, is_order_confirm_send=False, total_price_with_tax__gt=DECIMAL_ZERO, ) for customer_invoice in customer_invoice_qs: customer_invoice.delete_if_unconfirmed(permanence) # 1 - Round to multiple producer_order_by_quantity offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, is_active=True, order_unit__lt=PRODUCT_ORDER_UNIT_DEPOSIT, producer_order_by_quantity__gt=1, quantity_invoiced__gt=0).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: # It's possible to round the ordered qty even If we do not manage stock if offer_item.manage_replenishment: needed = (offer_item.quantity_invoiced - offer_item.stock) else: needed = offer_item.quantity_invoiced if needed > DECIMAL_ZERO: offer_item.add_2_stock = offer_item.producer_order_by_quantity - ( needed % offer_item.producer_order_by_quantity) offer_item.save() # 2 - Add Transport offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, is_active=False, order_unit=PRODUCT_ORDER_UNIT_TRANSPORTATION).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: buying_group = Customer.objects.filter( is_active=True, represent_this_buyinggroup=True).order_by('?').first() create_or_update_one_purchase( buying_group.id, offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False) for customer in Customer.objects.filter( is_active=True, may_order=True, customerinvoice__permanence_id=permanence.id, customerinvoice__total_price_with_tax__gt=DECIMAL_ZERO, represent_this_buyinggroup=False).order_by('?'): # 3 - Add Deposit offer_item_qs = OfferItem.objects.filter( permanence_id=permanence.id, order_unit=PRODUCT_ORDER_UNIT_DEPOSIT).order_by('?') if not all_producers: offer_item_qs = offer_item_qs.filter(producer_id__in=producers_id) for offer_item in offer_item_qs: create_or_update_one_purchase( customer.id, offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False) create_or_update_one_purchase( customer.id, offer_item, q_order=0, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False) if all_producers: permanence.set_status(PERMANENCE_CLOSED, allow_downgrade=False) if not repanier.apps.REPANIER_SETTINGS_INVOICE and repanier.apps.REPANIER_SETTINGS_BANK_ACCOUNT is None: # No Invoice and no bank_account --> auto archive # Put send permanences to the done status, because they will "never" be invoiced for permanence in Permanence.objects.filter( status=PERMANENCE_SEND): permanence.set_status(PERMANENCE_ARCHIVED, update_payment_date=True) else: permanence.set_status(PERMANENCE_CLOSED, all_producers=all_producers, producers_id=producers_id)