Exemple #1
0
def sync_prices(obj_ids, new_data):
    for id in obj_ids:
        # Update products
        Product.objects.filter(retailcrm_id=id).update(
            article=new_data[id]['article'],
            #
            price=new_data[id]['price'],
            discount_price=new_data[id]['discount_price'] or None,
            count_available=new_data[id]['count_available'],
            in_stock=True if new_data[id]['count_available'] > 0 else False,
        )
        p = Product.objects.get(retailcrm_id=id)
        # Create offers
        for offer_id in new_data[id]['offer_ids']:
            ProductOffer.objects.get_or_create(
                product=p,
                offer_id=offer_id,
            )
        # delete old offers (removed by user from RetailCRM)
        (ProductOffer.objects.filter(product=p).exclude(
            offer_id__in=new_data[id]['offer_ids']).delete())
    for kit in Product.objects.filter(is_product_kit=True):
        max_count = 9999
        for ki in kit.kit_items.all():
            p = Product.objects.get(id=ki.product.id)
            available = p.count_available
            if p.preorder != None or p.is_market_test:
                available = 9999
            max_for_ki = available / ki.count
            if max_count > max_for_ki:
                max_count = max_for_ki
        Product.objects.filter(id=kit.id).update(
            count_available=max_count,
            in_stock=True if max_count > 0 else False,
        )

    # Наборы: принудительно сбрасываем остатки и закупочные цены в CRM
    payload = []
    for kit in Product.objects.filter(is_product_kit=True):
        payload.append({
            'id':
            kit.retailcrm_offers.all()[0].offer_id,
            'stores': [{
                'code': 'smarta-red-room',
                'available': 9999,
                'purchasePrice':
                0.01,  # XXX проблема RetailCRM: 0 рублей выставить нельзя
            }],
        })
    url = "{}{}".format(BASE_URL, '/store/inventories/upload')

    r = requests.post(url,
                      data={
                          'apiKey': settings.RETAILCRM_API_SECRET,
                          'site': SHOP_ID,
                          'offers': json.dumps(payload),
                      })
    process_api_error(r, context_message=u"fixing kit count & purchasePrice")
Exemple #2
0
    def handle(self, *args, **options):
        # Use ods2json script from node.js to confert Excel to JSON
        data = json.loads(open('./data/frontpad-clients.json').read())
        # pprint(data)
        t = data['body']['tables'][0]

        EXISTING_CLIENT_NUMBERS = set()
        args = []
        for data in paginate_retailcrm('/customers', args):
            for c in data['customers']:
                for ph in c['phones']:
                    EXISTING_CLIENT_NUMBERS.add(_normalize_phone(ph['number']))
        pprint(EXISTING_CLIENT_NUMBERS)
        assert len(EXISTING_CLIENT_NUMBERS) > 100

        # Филиал | Имя | Телефон | Улица | Дом | Подъезд | Этаж | Квартира | Комментарий | Email | Не отправлять SMS | Дисконтная карта | Скидка | Лицевой счет | День рождения | Создан | Канал продаж |
        # x, name, phone, street, home, y, z, apt, comment, email, no_sms, card, discount, account, birthday, created, channel
        for num, row in enumerate(t['rows'][1:]):
            x, name, phone, street, home, y, z, apt, comment, email, no_sms, card, discount, account, birthday, created, channel = map(
                lambda c: c['value'], row['cells'])

            addr_list = [street]
            if home:
                addr_list.append(u'дом ' + home)
            if apt:
                addr_list.append(u'кв. ' + apt)
            address = u', '.join(addr_list)
            if u'перово' in address.lower() and u'утренняя' in address.lower(
            ) and '14' in address.lower():
                address = ''

            phones = map(lambda x: _normalize_phone(x.strip()),
                         phone.split(','))
            # print name, '|', phones, '|', comment, '|', email, '|', created, '|', address

            found = False
            for p in phones:
                if p in EXISTING_CLIENT_NUMBERS:
                    print "-- ALREADY FOUND -- add manually"
                    print "      ", name, '|', phones, '|', comment, '|', email, '|', created, '|', address
                    found = True
            if found:
                continue

            created_iso = datetime.strptime(created,
                                            '%d.%m.%Y').date().isoformat()

            print "  adding ", name
            payload = {
                'firstName': name,
                'email': email,
                'commentary': comment,
                'phones': [{
                    'number': p
                } for p in phones],
                'address': {
                    'text': address
                },
                'createdAt': created_iso + ' 00:00:00',
                'contragent': {
                    'contragentType': 'individual'
                },
                'externalId': 'frontpad2016__{}'.format(num),
            }
            pprint(payload)
            url = "{}{}".format(BASE_URL, '/customers/create')
            r = requests.post(url,
                              data={
                                  'apiKey': settings.RETAILCRM_API_SECRET,
                                  'site': SHOP_ID,
                                  'customer': json.dumps(payload),
                              })
            process_api_error(r)
Exemple #3
0
def fix_offers():
    u"""Workaround for a bug:
    if a product has multiple offers, and "common price for all" is checked,
    it still thinks there's no price for 2nd, 3rd, etc offer.

    We just update it here.
    """
    for data in paginate_retailcrm('/store/products', {
        'limit': '100',            
    }):
        for p in data['products']:
            offers = p['offers']

            need_fix = False
            valid_price_list = deepcopy(offers[0]['prices'])
            # 0. нулевая цена должна существовать и равняться нулю
            null_prices = filter(lambda p: p['priceType'] == 'null', valid_price_list)
            if not null_prices:
                valid_price_list.append({'price': 0, 'priceType': 'null'})
            for np in null_prices:
                if np['price'] != 0:
                    np['price'] = 0
            # 1. цены должны быть одинаковыми
            for o in offers:
                # sort so they can match
                o['prices'].sort(key=lambda p: p['priceType'])
                valid_price_list.sort(key=lambda p: p['priceType'])
                # check
                if o['prices'] != valid_price_list:
                    need_fix = True

            # 2. Исправляем
            if need_fix:
                print 
                print 
                print 
                # print "Prices not equal for:"
                # pprint(offers)
                # print "updating...."
                # prices[][prices][] array of objects (PriceUploadPricesInput)Цена торгового предложения
                # prices[][prices][][code] string Код типа цены
                # prices[][prices][][price] float Цена
                payload = []

                # XXX лишние цены не удаляются!
                for o in offers:
                    payload.append({
                        'id': o['id'],
                        'site': SHOP_ID,
                        'prices': [{'price': p['price'], 'code': p['priceType']} for p in valid_price_list],
                    })
                print "fixing with: "
                pprint(payload)
                url = "{}{}".format(BASE_API_URL, '/store/prices/upload')
                r = requests.post(url, data={
                    'apiKey': settings.RETAILCRM_API_SECRET,
                    'site': SHOP_ID,
                    'prices': json.dumps(payload),
                })
                if not process_api_error(r, silent=True, context_message=u"fixing offer prices"):
                    continue
                sleep(0.5) # FIXME consolidate instead, 250 max                    
Exemple #4
0
def sync_prices(obj_ids, new_data):
    for id in obj_ids:
        # Update products
        Product.objects.filter(retailcrm_id=id).update(
            article=new_data[id]['article'],
            #
            price=new_data[id]['price'],
            discount_price=new_data[id]['discount_price'] or None,
            count_available=new_data[id]['count_available'],
            in_stock=True if new_data[id]['count_available'] > 0 else False,
        )
        p = Product.objects.get(retailcrm_id=id)
        # Create offers
        for offer_id in new_data[id]['offer_ids']:
            ProductOffer.objects.get_or_create(
                product=p, 
                offer_id=offer_id,
            )
        # delete old offers (removed by user from RetailCRM)
        (ProductOffer.objects
         .filter(product=p)
         .exclude(offer_id__in=new_data[id]['offer_ids'])
         .delete()
        )

    # Save count by stores
    store_dict = dict((s.retailcrm_slug, s) for s in Store.objects.all())
    for data in paginate_retailcrm('/store/inventories', {
        'filter[details]': '1',
        'filter[offerActive]': '1',            
        'limit': '250',
    }):
        for offer in data['offers']:
            product = ProductOffer.objects.get(offer_id=offer['id']).product
            all_stores = set(slug for slug, store in store_dict.items())
            # Existing stores - set quantity
            for store in offer['stores']:
                if product.is_product_kit:
                    continue
                if store['store'] not in all_stores:
                    continue
                all_stores.remove(store['store'])
                try:
                    store_dict[store['store']]
                except KeyError:
                    log.exception('Need to add store to website', extra={
                        'store': store['store'],
                        'product': product.short_name,
                    })
                    continue
                try:
                    oc = ProductOfferCount.objects.get(
                        offer__offer_id=offer['id'],
                        store=store_dict[store['store']],
                    )
                except ProductOfferCount.DoesNotExist:
                    oc = ProductOfferCount(
                        offer=ProductOffer.objects.get(offer_id=offer['id']),
                        store=store_dict[store['store']],
                    )
                oc.count = store['quantity']
                oc.save()
            # Stores not returned listed - zero quantity
            for s in all_stores:
                try:
                    oc = ProductOfferCount.objects.get(
                        offer__offer_id=offer['id'],
                        store=Store.objects.get(retailcrm_slug=s),
                    )
                except ProductOfferCount.DoesNotExist:
                    oc = ProductOfferCount(
                        offer=ProductOffer.objects.get(offer_id=offer['id']),
                        store=Store.objects.get(retailcrm_slug=s),
                    )
                oc.count = 0
                oc.save()
        
    # [OLD] calculate counts of product kits
    for kit in Product.objects.filter(is_product_kit=True):
        max_count = 9999
        for ki in kit.kit_items.all():
            if ki.count <= 0:
                continue
            p = Product.objects.get(id=ki.product.id)
            available = p.count_available
            if p.preorder != None or p.is_market_test:
                available = 9999
            max_for_ki = available / ki.count
            if max_count > max_for_ki:
                max_count = max_for_ki
        Product.objects.filter(id=kit.id).update(
            count_available=max_count,
            in_stock=True if max_count > 0 else False,
        )
    # Calculate counts of product kits by store
    INFINITY = 9999
    for store in Store.objects.all():
        for kit in Product.objects.filter(is_product_kit=True):
            max_count = INFINITY
            for ki in kit.kit_items.all():
                p = Product.objects.get(id=ki.product.id)
                available = p.count_available
                if p.preorder != None or p.is_market_test:
                    available = INFINITY
                ki_count_on_store = ki.get_count_on_store(store)
                max_for_ki = available / ki.get_count_on_store(store) if ki_count_on_store else INFINITY
                if max_count > max_for_ki:
                    max_count = max_for_ki

            if max_count == INFINITY:
                max_count = 0

            kit_makeable_count, created = ProductKitMakeableCount.objects.get_or_create(
                product=kit,
                store=store,
                defaults={'count': 0},
            )
            kit_makeable_count.count = max_count
            kit_makeable_count.save()

    # Наборы: принудительно сбрасываем остатки и закупочные цены в CRM
    payload = []
    for kit in Product.objects.filter(is_product_kit=True):
        payload.append({
            'id': kit.retailcrm_offers.all()[0].offer_id,
            'stores': [{
                'code': store,
                'available': 9999,
                'purchasePrice': 0.01, # XXX проблема RetailCRM: 0 рублей выставить нельзя
            } for store in settings.RETAILCRM_ALL_STORES],
        })
    url = "{}{}".format(BASE_API_URL, '/store/inventories/upload')

    r = requests.post(url, data={
        'apiKey': settings.RETAILCRM_API_SECRET,
        'site': SHOP_ID,
        'offers': json.dumps(payload),
    })
    process_api_error(r, context_message=u"fixing kit count & purchasePrice")