Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import os
  2. import re
  3. from django.utils.translation import ugettext_lazy as _
  4. from django.db import models
  5. from django.utils.timezone import now
  6. from oscar.core.compat import AUTH_USER_MODEL
  7. Product = models.get_model('catalogue', 'Product')
  8. class RangeProductFileUpload(models.Model):
  9. range = models.ForeignKey('offer.Range', related_name='file_uploads', verbose_name=_("Range"))
  10. filepath = models.CharField(_("File Path"), max_length=255)
  11. size = models.PositiveIntegerField(_("Size"))
  12. uploaded_by = models.ForeignKey(AUTH_USER_MODEL, verbose_name=_("Uploaded By"))
  13. date_uploaded = models.DateTimeField(_("Date Uploaded"), auto_now_add=True)
  14. PENDING, FAILED, PROCESSED = 'Pending', 'Failed', 'Processed'
  15. choices = (
  16. (PENDING, PENDING),
  17. (FAILED, FAILED),
  18. (PROCESSED, PROCESSED),
  19. )
  20. status = models.CharField(_("Status"), max_length=32, choices=choices, default=PENDING)
  21. error_message = models.CharField(_("Error Message"), max_length=255, blank=True)
  22. # Post-processing audit fields
  23. date_processed = models.DateTimeField(_("Date Processed"), null=True)
  24. num_new_skus = models.PositiveIntegerField(_("Number of New SKUs"), null=True)
  25. num_unknown_skus = models.PositiveIntegerField(_("Number of Unknown SKUs"), null=True)
  26. num_duplicate_skus = models.PositiveIntegerField(_("Number of Duplicate SKUs"), null=True)
  27. class Meta:
  28. ordering = ('-date_uploaded',)
  29. verbose_name = _("Range Product Uploaded File")
  30. verbose_name_plural = _("Range Product Uploaded Files")
  31. @property
  32. def filename(self):
  33. return os.path.basename(self.filepath)
  34. def mark_as_failed(self, message=None):
  35. self.date_processed = now()
  36. self.error_message = message
  37. self.status = self.FAILED
  38. self.save()
  39. def mark_as_processed(self, num_new, num_unknown, num_duplicate):
  40. self.status = self.PROCESSED
  41. self.date_processed = now()
  42. self.num_new_skus = num_new
  43. self.num_unknown_skus = num_unknown
  44. self.num_duplicate_skus = num_duplicate
  45. self.save()
  46. def was_processing_successful(self):
  47. return self.status == self.PROCESSED
  48. def process(self):
  49. """
  50. Process the file upload and add products to the range
  51. """
  52. all_ids = set(self.extract_ids())
  53. products = self.range.included_products.all()
  54. existing_skus = set(filter(bool, products.values_list('stockrecord__partner_sku', flat=True)))
  55. existing_upcs = set(filter(bool, products.values_list('upc', flat=True)))
  56. existing_ids = existing_skus.union(existing_upcs)
  57. new_ids = all_ids - existing_ids
  58. products = Product._default_manager.filter(
  59. models.Q(stockrecord__partner_sku__in=new_ids) |
  60. models.Q(upc__in=new_ids))
  61. for product in products:
  62. self.range.included_products.add(product)
  63. # Processing stats
  64. found_skus = set(filter(bool, products.values_list('stockrecord__partner_sku', flat=True)))
  65. found_upcs = set(filter(bool, products.values_list('upc', flat=True)))
  66. found_ids = found_skus.union(found_upcs)
  67. missing_ids = new_ids - found_ids
  68. dupes = set(all_ids).intersection(existing_ids)
  69. self.mark_as_processed(products.count(), len(missing_ids), len(dupes))
  70. def extract_ids(self):
  71. """
  72. Extract all SKU- or UPC-like strings from the file
  73. """
  74. for line in open(self.filepath, 'r'):
  75. for id in re.split('[^\w:\.-]', line):
  76. if id:
  77. yield id
  78. def delete_file(self):
  79. os.unlink(self.filepath)