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")
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)
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
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")