AlexProfi

alitvin

May 30th, 2017
206
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.16 KB | None | 0 0
  1. #models.py
  2.  
  3. from __future__ import unicode_literals
  4. import datetime
  5. import base64
  6. from django.core.exceptions import ValidationError
  7. from django.http import QueryDict
  8. from django.utils import timezone
  9. import urllib2
  10. from random import randint
  11. from django.template.defaultfilters import length
  12.  
  13. import json
  14. from pyxtension.Json import Json
  15.  
  16. from yandex_money.models import Payment
  17. from robokassa.models import SuccessNotification
  18. from paypal.standard.ipn.models import PayPalIPN
  19.  
  20. import requests
  21.  
  22. from django.contrib.auth.models import User
  23. from django.core.cache import cache
  24. from django.core.urlresolvers import reverse
  25. from django.db import models
  26. from django.db.models import Q, Sum
  27. from django.template.loader import get_template
  28. from django.utils.functional import cached_property
  29. from django.utils.safestring import mark_safe
  30.  
  31. from core.models import ArticlePage, CartItemMixin
  32. from utils import gen_random_string
  33.  
  34. from math import *
  35.  
  36.  
  37. def robokassa_order_number():
  38.     number = gen_random_string(9, symbols='digits')
  39.     if number.startswith('0'):
  40.         number = str(randint(1, 9)) + number[1:]
  41.     return number
  42.  
  43. class DeliveryInfo(models.Model):
  44.     template_name = 'delivery_info.html'
  45.     DTYPES = [
  46.         ('b2cpl', u'По России'),
  47.         ('ems', u'EMS'),
  48.     ]
  49.  
  50.     user = models.OneToOneField(UserProfile, related_name=u'delivery', verbose_name=u'Пользователь', blank=True,
  51.                                 null=True)
  52.     order = models.OneToOneField(Order, related_name='delivery', verbose_name=u'Заказ', blank=True, null=True)
  53.     name = models.CharField(u'Имя Фамилия Отчество', max_length=255)
  54.     phone = models.CharField(u'Телефон', max_length=255)
  55.     email = models.CharField(u'E-mail', max_length=255)
  56.     zipcode = models.CharField(u'Индекс', max_length=6, blank=True, null=True)
  57.     country = models.ForeignKey(Country, models.SET_NULL, verbose_name=u'Страна', blank=True, null=True)
  58.     city = models.CharField(u'Город', max_length=255, blank=True, null=True)
  59.     address = models.CharField(u'Место проживания', max_length=255, blank=True, null=True)
  60.     dtype = models.CharField(u'Тип доставки', choices=DTYPES, default='b2cpl', max_length=10, blank=True, null=True)
  61.     last_delivery_price = models.PositiveIntegerField(default=0)
  62.     code = models.CharField(u'Код доставки', max_length=50, default=u'курьер', blank=True, null=True)
  63.     options = models.CharField(u'Информация о доставке', max_length=2000, blank=True, null=True)
  64.  
  65.     class Meta:
  66.         verbose_name = u'запись'
  67.         verbose_name_plural = u'Форма "Контактная информация"'
  68.  
  69.     def __unicode__(self):
  70.         return self.name
  71.  
  72.     def _get_ship_options(self):
  73.         if self.options and isinstance(self.options, dict):
  74.             return Json(self.options)
  75.  
  76.     _get_ship_options.short_description = 'Опции доставки'
  77.     ship_options = property(_get_ship_options)
  78.  
  79.     # Адрес пвз если доставка туда
  80.     def _get_ship_pvz_address(self):
  81.         if self.ship_options:
  82.             param = self.ship_options['Адрес']
  83.             if length(param) > 0:
  84.                 return param
  85.  
  86.     _get_ship_pvz_address.short_description = 'Адрес ПВЗ'
  87.     ship_pvz_address = property(_get_ship_pvz_address)
  88.  
  89.     def get_info(self, plain=False):
  90.         data = [
  91.             {'value': getattr(self, 'name', '-'), 'label': u'Имя Фамилия Отчество'},
  92.             {'value': getattr(self, 'phone', '-'), 'label': u'Телефон'},
  93.             {'value': getattr(self, 'email', '-'), 'label': u'E-mail'},
  94.             {'value': getattr(self, 'zipcode', '-'), 'label': u'Индекс'},
  95.             {'value': getattr(self, 'country', '-'), 'label': u'Страна'},
  96.             {'value': getattr(self, 'city', '-'), 'label': u'Город'},
  97.             {'value': getattr(self, 'address', '-'), 'label': u'Место проживания'},
  98.             {'value': self.dtype_verbose, 'label': u'Тип доставки'},
  99.         ]
  100.         if self.dtype_verbose == 'b2cpl':
  101.             data.__add__({'value': getattr(self, 'options', '-')['Код'], 'label': u'Вариант доставки'})
  102.         if plain:
  103.             return u'\r\n'.join([u'{0}: {1}'.format(item['label'], item['value']) for item in data])
  104.         else:
  105.             html = get_template(self.template_name)
  106.             html = html.render({'data': data})
  107.             return html
  108.  
  109.     @property
  110.     def dtype_verbose(self):
  111.         return dict(self.DTYPES).get(self.dtype)
  112.  
  113.     def get_cost(self, request, weight):
  114.         cost = 0
  115.         options = None
  116.         q = QueryDict('', mutable=True)
  117.  
  118.         if self.dtype == 'b2cpl':
  119.             # Формируем ссылку для запроса через API
  120.             params = {'func': 'tarif', 'type': '+post', 'zip': self.zipcode, 'weight': str(int(weight))}
  121.             q.update(params)
  122.             url = '%s?%s' % (reverse('cart:b2c_api'), q.urlencode(safe='/'))
  123.  
  124.             data = requests.get(request.build_absolute_uri(url)).json()
  125.             if data.get('flag_delivery'):
  126.                 ways = data['delivery_ways']
  127.                 for way in ways:
  128.                     if way.get('Код') == self.code:
  129.                         options = way
  130.                         cost = options['Стоимость']
  131.                         break
  132.  
  133.         elif self.dtype == 'ems':
  134.             params = {'method': 'ems.calculate', 'type': 'att', 'to': self.country.code, 'weight': str(weight)}
  135.             q.update(params)
  136.             url = '%s?%s' % (reverse('cart:ems_api'), q.urlencode(safe='/'))
  137.  
  138.             data = requests.get(request.build_absolute_uri(url)).json()
  139.             if data['rsp']['stat'] == 'ok':
  140.                 cost = data['rsp']['price']
  141.  
  142.         if options:
  143.             self.options = json.dumps(options)
  144.         if cost:
  145.             cost = int(round(float(cost.replace(',', "."))))
  146.             return cost
  147.         else:
  148.             raise ValidationError(('Доставка с кодом: %(value)s невозможна, выберите другой вариант.'),
  149.                                   code='delivery_unpossible',
  150.                                   params={'value': self.code}, )
  151.  
  152. #views.py
  153.  
  154. class DeliveryFormView(UpdateView):
  155.     form_class = DeliveryForm
  156.     model = DeliveryInfo
  157.     session_key = 'dform_id'
  158.     tab = 'delivery'
  159.  
  160.     def get(self, request):
  161.         raise Http404
  162.  
  163.     def get_object(self):
  164.         return CabinetPage.get_form_instance(self.request, self.model, self.session_key)
  165.  
  166.     def form_valid(self, form):
  167.         profile = self.get_or_create_user_profile(self.request)
  168.         # if form.instance.user != profile:
  169.         #     form.instance.user = profile
  170.         # form.save()
  171.         delivery, created = DeliveryInfo.objects.get_or_create(user=profile)
  172.         if self.request.POST.get('name'):
  173.             delivery.name = self.request.POST.get('name')
  174.         if self.request.POST.get('phone'):
  175.             delivery.phone = self.request.POST.get('phone')
  176.         if self.request.POST.get('email'):
  177.             delivery.email = self.request.POST.get('email')
  178.         if self.request.POST.get('zipcode'):
  179.             delivery.zipcode = self.request.POST.get('zipcode')
  180.         if self.request.POST.get('country'):
  181.             try:
  182.                 delivery.country = Country.objects.get(id=self.request.POST.get('country'))
  183.             except Country.DoesNotExist:
  184.                 pass
  185.         if self.request.POST.get('city'):
  186.             delivery.city = self.request.POST.get('city')
  187.         if self.request.POST.get('address'):
  188.             delivery.address = self.request.POST.get('address')
  189.         delivery.code = form.cleaned_data['code']
  190.         if self.request.POST.get('dtype'):
  191.             delivery.dtype = self.request.POST.get('dtype')
  192.             weight = CartForm.get_weight(self.request)
  193.             try:
  194.                 delivery.last_delivery_price = delivery.get_cost(self.request, weight)
  195.             except ValidationError as e:
  196.                 if e.code:
  197.                     if e.code == 'delivery_unpossible':
  198.                         form.add_error('code', ''.join(e.messages))
  199.                 return JsonResponse({'success': False, 'status': 'error', 'errors': form.errors})
  200.         delivery.save()
  201.         self.request.session[self.session_key] = form.instance.id
  202.         CabinetPage.manage_tabs(self.request, self.tab, 'add')
  203.  
  204.         return JsonResponse({'success': True, 'status': 'ok'})
  205.  
  206.     def form_invalid(self, form):
  207.         print(form.errors)
  208.         CabinetPage.manage_tabs(self.request, self.tab, 'delete')
  209.         return JsonResponse({'success': False, 'status': 'error', 'errors': form.errors})
  210.  
  211.     def get_or_create_user_profile(self, request):
  212.         profile = getattr(request.user, 'profile', None) or UserProfile.objects.filter(
  213.             id=request.session.get('profile_id')).first()
  214.         if not profile:
  215.             profile = UserProfile()
  216.             profile.save()
  217.             request.session['profile_id'] = profile.id
  218.         return profile
  219.  
  220. #robokassa/views
  221.  
  222. from robokassa.conf import USE_POST
  223. from robokassa.forms import RobokassaForm, ResultURLForm, SuccessRedirectForm, FailRedirectForm
  224. from robokassa.signals import result_received, success_page_visited, fail_page_visited
  225. from robokassa.models import SuccessNotification
  226.  
  227. from django.views.decorators.csrf import csrf_exempt
  228. from django.http import HttpResponseRedirect
  229. from django.conf import settings
  230. from cart.export import export_orders_to_b2c
  231.  
  232. from cart.models import Order
  233. from cart.forms import SendBillForm
  234. from pay.views import SendPaymentView
  235.  
  236.  
  237. def get_order(order_number):
  238.     try:
  239.         return Order.objects.get(order_number=order_number)
  240.     except Order.DoesNotExist:
  241.         return None
  242.  
  243.  
  244. def payment_received(sender, **kwargs):
  245.     order = get_order(order_number=kwargs['InvId'])
  246.     if not order:
  247.         return
  248.     order.status = 'success'
  249.     order.robokassa_payment = SuccessNotification.objects.filter(InvId=kwargs['InvId']).first()
  250.     order.date = datetime.datetime.now()
  251.     order.save()
  252.     if order.has_delivery and order.delivery.dtype == 'b2cpl':
  253.         export_orders_to_b2c(kwargs['request'], order)
  254.     SendBillForm().send_email(order=order)
  255.  
  256. result_received.connect(payment_received)
  257.  
  258. #export.py
  259.  
  260. import datetime
  261. import io
  262. import os
  263. import urlparse
  264. import uuid
  265. from django.core.urlresolvers import reverse
  266. from contextlib import closing
  267. import unicodecsv
  268.  
  269. import xlwt
  270. import requests
  271. import codecs
  272.  
  273. from django.db.models import Sum
  274. from django.http import HttpResponse, QueryDict
  275. from _conf.core import B2CPL_EXPORT_FIELDS, MEDIA_ROOT, B2CPL_EXPORT_DIR, B2CPL_PACKAGE_TYPE
  276.     # Настройки для загрузки файлов ответов B2cpl после импорта заказа в их систему
  277.  
  278. from cart.models import OrderItem
  279.  
  280. def export_orders_to_b2c(request, order):
  281.     col_delim = ';'
  282.     row_delim = '\r\n'
  283.  
  284.     fname = str(uuid.uuid4()) + '.csv'
  285.     fout = os.path.join(MEDIA_ROOT, B2CPL_EXPORT_DIR, fname)
  286.  
  287.     with codecs.open(fout, "wb+") as f:
  288.         w = unicodecsv.DictWriter(f, encoding='utf-8', fieldnames=B2CPL_EXPORT_FIELDS, extrasaction='raise',
  289.                                   delimiter=str(col_delim), lineterminator=row_delim, skipinitialspace=True)
  290.  
  291.         # header fields
  292.         w.writeheader()
  293.  
  294.         # body
  295.         rec = {}
  296.         delivery = order.delivery
  297.         rec['Дата заказа'] = order.date.strftime('%d/%m/%Y')
  298.         rec['Индекс'] = delivery.zipcode
  299.         rec['Город'] = delivery.city
  300.         rec['Адрес'] = delivery.address
  301.         rec['ФИО'] = delivery.name
  302.         rec['E-mail'] = delivery.email
  303.         rec['Телефон мобильный'] = delivery.phone
  304.  
  305.         # TODO выяснить назначение этих полей. Вроде вся доставка учтена при оплате
  306.         # rec['Полная стоимость доставки'] = delivery.last_delivery_price
  307.         # rec['Стоимость доставки к оплате'] = delivery.last_delivery_price
  308.         rec['Полная стоимость доставки'] = 0
  309.         rec['Стоимость доставки к оплате'] = 0
  310.         rec['Тип доставки'] = delivery.code
  311.         # TODO Uncomment to enable
  312.         rec['Упаковка'] = B2CPL_PACKAGE_TYPE
  313.  
  314.         items2delivery = order.items.filter(dtype__in=['calendar', 'book'], export_name__isnull=False).distinct()
  315.         sum_items2delivery = sum([item.sum for item in items2delivery]) if items2delivery else 0
  316.         rec['Оценочная стоимость посылки'] = sum_items2delivery
  317.  
  318.         for item in items2delivery:
  319.             rec['Номер посылки'] = order.order_number
  320.             rec['Артикул'] = item.export_name
  321.             rec['Товар'] = item.title
  322.             rec['Кол-во ед. товара'] = item.amount
  323.             rec['Полная стоимость ед. товара'] = item.page.productarticle.price
  324.             rec['Стоимость ед. товара к оплате'] = 0
  325.             # rec['Вес товара'] = item.page.weight
  326.  
  327.             w.writerow(rec)
  328.             rec = {}
  329.  
  330.     protocol = request.scheme
  331.     host = request.META['HTTP_HOST']
  332.  
  333.     fout_rel = urlparse.urljoin(protocol + '://' + host, os.path.relpath(fout))
  334.  
  335.     q = QueryDict('', mutable=True)
  336.     params = {'func': 'upload', 'file': fout_rel, 'report': '1', 'stickers': '0'}
  337.     q.update(params)
  338.     url = '%s?%s' % (reverse('cart:b2c_api'), q.urlencode(safe='/'))
  339.  
  340.     absoluteUri = request.build_absolute_uri(url)
  341.     print('absoluteUri: ' + absoluteUri)
  342.  
  343.     data = requests.get(absoluteUri).json()
  344.  
  345.     if data.get('cnt_ok'):
  346.         packs = data.get('packages')
  347.         track_number = packs[0]['codeb2c']
  348.         if track_number:
  349.             order.tracking_number = track_number
  350.             order.save()
  351.             order.send_email(tracking=True)
  352.     return data
Add Comment
Please, Sign In to add comment