You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
7.6 KiB
184 lines
7.6 KiB
# -*- coding: utf-8 -*-
|
|
from collections import OrderedDict
|
|
from xml.etree import ElementTree as ET
|
|
from datetime import datetime
|
|
from datetime import date
|
|
from datetime import timedelta
|
|
|
|
from suds.client import Client
|
|
from suds.xsd.doctor import ImportDoctor, Import
|
|
# import requests
|
|
|
|
from django.db.models.sql.where import AND, OR
|
|
from django.utils.translation import ugettext as _
|
|
from django.conf import settings
|
|
from django.core.cache import cache
|
|
|
|
from functions.model_utils import EnumChoices
|
|
|
|
members_mapping = OrderedDict([
|
|
('N200', {'min': None, 'max': 200, 'value': 1, 'label': _(u'до 200')}),
|
|
('N200500', {'min': 200, 'max': 400, 'value': 2, 'label': _(u'200-500')}),
|
|
('N5001000', {'min': 500, 'max': 500, 'value': 3, 'label': _(u'500-1000')}),
|
|
('N10002000', {'min': 1000, 'max': 2000, 'value': 4, 'label': _(u'1000-2000')}),
|
|
('N2000', {'min': 2000, 'max': None, 'value': 5, 'label': _(u'более 2000')}),
|
|
])
|
|
|
|
visitors_mapping = OrderedDict([
|
|
('N5', {'min': None, 'max': 5000, 'value': 1, 'label': _(u'до 5 000')}),
|
|
('N510', {'min': 5000, 'max': 10000, 'value': 2, 'label': _(u'5 000 - 10 000')}),
|
|
('N1030', {'min': 10000, 'max': 30000, 'value': 3, 'label': _(u'10 000 - 30 000')}),
|
|
('N3050', {'min': 30000, 'max': 50000, 'value': 4, 'label': _(u'30 000 - 50 000')}),
|
|
('N50100', {'min': 50000, 'max': 100000, 'value': 5, 'label': _(u'50 000 - 100 000')}),
|
|
('N100', {'min': 100000, 'max': None, 'value': 6, 'label': _(u'более 100 000')}),
|
|
])
|
|
|
|
price_mapping = OrderedDict([
|
|
('N0', {'min': None, 'max': None, 'value': 0, 'label': _(u'Не указана')}),
|
|
('N5', {'min': 1, 'max': 5000, 'value': 1, 'label': _(u'до 5000 руб.')}),
|
|
('N510', {'min': 5000, 'max': 10000, 'value': 2, 'label': _(u'5000-10000 руб.')}),
|
|
('N1020', {'min': 10000, 'max': 20000, 'value': 3, 'label': _(u'10000-20000 руб.')}),
|
|
('N20', {'min': 20000, 'max': None, 'value': 4, 'label': _(u'более 20000 руб.')}),
|
|
])
|
|
|
|
price_mapping_eur = OrderedDict([
|
|
('N0', {'min': None, 'max': None, 'value': 0, 'label': _(u'Не указана')}),
|
|
('N5', {'min': 1, 'max': 100, 'value': 1, 'label': _(u'до 100 евро')}),
|
|
('N510', {'min': 100, 'max': 200, 'value': 2, 'label': _(u'100-200 евро')}),
|
|
('N1020', {'min': 200, 'max': 400, 'value': 3, 'label': _(u'200-400 евро')}),
|
|
('N20', {'min': 400, 'max': None, 'value': 4, 'label': _(u'более 400 евро')}),
|
|
])
|
|
|
|
def get_choices_kwargs(mapping):
|
|
kwargs = OrderedDict()
|
|
for key, val in mapping.iteritems():
|
|
kwargs[key] = (val.get('value'), val.get('label'))
|
|
return kwargs
|
|
|
|
MEMBERS = EnumChoices(**get_choices_kwargs(members_mapping))
|
|
VISITORS = EnumChoices(**get_choices_kwargs(visitors_mapping))
|
|
PRICE = EnumChoices(**get_choices_kwargs(price_mapping))
|
|
PRICE_EUR = EnumChoices(**get_choices_kwargs(price_mapping_eur))
|
|
TYPES = EnumChoices(
|
|
EXPO=(1, _(u'Выставки')),
|
|
CONF=(2, _(_(u'Конференции'))),
|
|
)
|
|
|
|
|
|
class ExtraWhere(object):
|
|
def __init__(self, sqls, params, operator=AND):
|
|
self.sqls = sqls
|
|
self.params = params
|
|
self.operator = operator
|
|
|
|
def as_sql(self, qn=None, connection=None):
|
|
sqls = ["(%s)" % sql for sql in self.sqls]
|
|
operator = " {operator} ".format(operator=self.operator)
|
|
return operator.join(sqls), tuple(self.params or ())
|
|
|
|
|
|
class GetCourse(object):
|
|
"""GetCourse().convert(currency_id, amount)
|
|
http://www.cbr.ru/scripts/Root.asp
|
|
"""
|
|
cache_timeout = timedelta(hours=24).total_seconds
|
|
cache_key = getattr(settings, 'COURSE_CACHE_KEY', 'course_data_{0}')
|
|
target_char_code = 'RUB'
|
|
|
|
def __init__(self, nocache=False, *args, **kwargs):
|
|
self.nocache = True
|
|
# self.url = kwargs.get('url', 'http://www.cbr.ru/scripts/XML_daily.asp')
|
|
self.url = kwargs.get('url', 'http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx')
|
|
self.alllowed_codes = settings.CURRENCY
|
|
self.get_data()
|
|
|
|
def build_request_body(self):
|
|
top = ET.Element('soap:Envelope')
|
|
top.attrib.update({
|
|
'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
|
|
'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
|
|
'xmlns:soap': "http://schemas.xmlsoap.org/soap/envelope/",
|
|
})
|
|
body = ET.SubElement(top, 'soap:Body')
|
|
operation = ET.SubElement(body, 'GetCursOnDate')
|
|
operation.attrib.update({
|
|
'xmlns': "http://web.cbr.ru/"
|
|
})
|
|
ondate = ET.SubElement(operation, 'On_date')
|
|
ondate.text = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
|
|
return '<?xml version="1.0" encoding="utf-8"?>\n {xml}'.format(xml=ET.tostring(top))
|
|
|
|
def make_cache_key(self):
|
|
return self.cache_key.format(date.today().isoformat())
|
|
|
|
def get_data(self):
|
|
courses = cache.get(self.make_cache_key())
|
|
if self.nocache:
|
|
# try:
|
|
# r = requests.post(
|
|
# url=self.url,
|
|
# data=self.build_request_body(),
|
|
# headers={'Content-Type': 'text/xml; charset=utf-8'})
|
|
# if r.status_code == requests.codes.ok:
|
|
# courses = self.parse_xml(r)
|
|
# cache.set(self.make_cache_key(), courses, self.cache_timeout)
|
|
# except:
|
|
# pass
|
|
# try:
|
|
|
|
# http://stackoverflow.com/questions/19831566/how-to-get-a-soap-body-by-using-soappy
|
|
imp = Import('http://www.w3.org/2001/XMLSchema')
|
|
imp.filter.add('http://web.cbr.ru/')
|
|
d = ImportDoctor(imp)
|
|
s = Client("http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl", doctor=d)
|
|
result = s.service.GetCursOnDate(datetime.now().replace(hour=0, minute=0, second=0, microsecond=0).isoformat())
|
|
courses = {}
|
|
for valute in result.diffgram.ValuteData.ValuteCursOnDate:
|
|
char_code = valute.VchCode
|
|
if char_code not in self.alllowed_codes:
|
|
continue
|
|
nominal = float(valute.Vnom)
|
|
value = float(valute.Vcurs)
|
|
courses[char_code] = round(value / nominal, 3)
|
|
# except:
|
|
# pass
|
|
self.courses = courses
|
|
|
|
def parse_xml(self, response):
|
|
root = ET.fromstring(response.text.encode(response.encoding))
|
|
courses = {}
|
|
for valute in root.iterfind('Valute'):
|
|
char_code = valute.find('CharCode').text
|
|
if char_code not in self.alllowed_codes:
|
|
continue
|
|
nominal = float(valute.find('Nominal').text.replace(',', '.'))
|
|
value = float(valute.find('Value').text.replace(',', '.'))
|
|
courses[char_code] = round(value / nominal, 3)
|
|
return courses
|
|
|
|
@property
|
|
def can_convert(self):
|
|
return self.courses is not None
|
|
|
|
def convert(self, char_code, amount):
|
|
'''Returns converted amount and bool indicating convert state
|
|
'''
|
|
if char_code == self.target_char_code:
|
|
return amount, True
|
|
if self.can_convert and char_code in self.courses.keys():
|
|
return int(round(amount * self.courses[char_code] * 1.03)), True
|
|
else:
|
|
return amount, False
|
|
|
|
def convert_or_null(self, char_code, amount):
|
|
if amount is None:
|
|
return 0
|
|
amount, converted = self.convert(char_code, amount)
|
|
return amount if amount else 0
|
|
|
|
def convert_to_eur_or_null(self, amount):
|
|
'''only from RUB
|
|
'''
|
|
if amount is None:
|
|
return 0
|
|
return int(round(amount / self.courses['EUR']))
|
|
|