コード例 #1
0
def prepare_deals(new_deals):
    bitrix_deals = get_bitrix_data(_deal_list,
                                   params={'select': ['UF_*', '*']})
    to_add = []
    to_remove = []
    to_update = []
    id_key = deal_fields_mapping.get('id booking (source)')
    for deal in new_deals:
        btx_deal = find_dict_in_list(lst=bitrix_deals,
                                     key=id_key,
                                     value=deal[id_key])

        if btx_deal:
            # a workaround for difference of precisions
            btx_deal['OPPORTUNITY'] = None if not btx_deal[
                'OPPORTUNITY'] else float(btx_deal['OPPORTUNITY'])

            if are_differ(deal, btx_deal, Cfg.get('btx_deal_mutable_fields')):
                deal['ID'] = btx_deal['ID']
                to_update.append(deal)

            bitrix_deals.remove(btx_deal)
        else:
            to_add.append(deal)

    for old_deal in bitrix_deals:
        to_remove.append(old_deal['ID'])

    return to_add, to_update, to_remove
コード例 #2
0
def advanced_request(target, ids=None, fields=None, params={}):
    # e.g. target is account and url will be accounts_base_url
    url_base = Cfg.get('bks_' + target + 's_base_url')

    params['per_page'] = Cfg.get('bks_x_per_page')
    if ids:
        params['id'] = ids
    if fields:
        params['fields'] = fields

    req = request_data(url_base, params)
    data = req[target + 's']
    total = int(req['meta']['X-Total-Pages'])
    if total > 1:
        params['per_page'] = req['meta']['X-Per-Page']
        for i in range(2, total + 1):
            params['page'] = i
            data += request_data(url_base, params)[target + 's']

    return data
コード例 #3
0
def upload_products(to_add, to_update, to_delete):
    logging.info('Updating Bitrix products...')
    if Cfg.get('btx_remove_old_rows'):
        delete_bitrix_fields(_product_remove, to_delete, 'products')
    update_bitrix_fields(_product_update, to_update, 'products')
    add_bitrix_fields(_product_add, to_add, 'products')
    logging.info('Updated: {}'.format(len(to_update)))
    logging.info('Added: {}'.format(len(to_add)))
    logging.info('Deleted: {}'.format(len(to_delete)))
    logging.info(
        'Note: The items above may not been delete if remove_old_rows flag is false'
    )
コード例 #4
0
def upload_deals(to_add, to_update, to_delete):
    get_contact_ids()
    get_product_ids()
    logging.info('Processing Bitrix deals...')
    if Cfg.get('btx_remove_old_rows'):
        delete_bitrix_fields(_deal_remove, to_delete, 'deals')

    update_bitrix_fields(_deal_update, to_update, 'deals')
    add_bitrix_fields(_deal_add, to_add, 'deals', add_contacts_to_deals)
    logging.info('Updated: {}'.format(len(to_update)))
    logging.info('Added: {}'.format(len(to_add)))
    logging.info('Deleted: {}'.format(len(to_delete)))
    logging.info(
        'Note: The items above may not been delete if remove_old_rows flag is false'
    )
コード例 #5
0
def get_products_from_db(db_data):
    products = []
    pm = product_fields_mapping
    for rental in db_data['rentals']:
        products.append({
            'NAME':
            rental['name'],
            'SECTION_ID':
            Cfg.get('btx_product_section_id'),
            pm['rental_id']:
            rental['id'],
            pm['street']:
            rental['address1'],
            pm['city']:
            rental['city'],
            'DESCRIPTION':
            '{}, {} {}'.format(rental['contact_name'], rental['address1'],
                               rental['city'])
        })
    return products
コード例 #6
0
def get_stage(start_at, end_at, status):
    # Deal stage: is something like status.
    # By default it is "booked".
    # If the reservation is 32days ahead or less we change it to :"payed".
    # If start_at is today, then we change it to "Arrival".
    # If start_at<today<end_at then value is "staying", and if end_at=today then "departing"
    stage_id = STAGE.BOOKED if status == 'Booked' else STAGE.CANCELED if status == 'Canceled' else None
    reserve_days_ahead = (start_at - datetime.now()).days
    try:
        if reserve_days_ahead == 0:
            stage_id = STAGE.ARRIVED
        elif start_at <= datetime.now() <= end_at:
            stage_id = STAGE.STAY
        elif datetime.now() > end_at:
            stage_id = STAGE.DEPARTED
        elif 0 < reserve_days_ahead <= Cfg.get('btx_payed_status_interval'):
            stage_id = STAGE.PAYED
    except Exception as e:
        logging.info('Problem when trying to count stage_id: {}'.format(
            str(e)))

    return stage_id
コード例 #7
0
def are_differ_products(bookingsync_record, bitrix_record):
    for _key, val1 in bookingsync_record.items():
        if _key not in Cfg.get('btx_product_mutable_fields'):
            continue

        val2 = bitrix_record[_key]

        if not val1 and not val2:
            continue

        if type(val2) == dict:
            if str(val1) != str(val2['value']):
                return True
        elif str(val1) != str(val2):
            try:
                logging.info('for {} key, differ {} and {}'.format(
                    _key, val1, val2))
            except UnicodeEncodeError:
                logging.info('for {} key, something is differ')

            return True

    return False
コード例 #8
0
def prepare_contacts(new_clients):
    bitrix_contacts = get_bitrix_data(
        _contact_list, params={'select': ['*', 'UF_*', 'PHONE', 'EMAIL']})
    to_add = []
    to_remove = []
    to_update = []
    for client in new_clients:
        btx_contact = find_dict_in_list(bitrix_contacts, contact_client_id_key,
                                        client['ID'])

        if btx_contact:
            if 'PHONE' not in btx_contact:
                btx_contact['PHONE'] = [{'VALUE': '', 'VALUE_TYPE': 'OTHER'}]
            if 'EMAIL' not in btx_contact:
                btx_contact['EMAIL'] = [{'VALUE': '', 'VALUE_TYPE': 'OTHER'}]

            assert type(btx_contact) == dict
            if are_differ(client, btx_contact,
                          Cfg.get('btx_contact_mutable_fields')):
                for i, p in enumerate(client['PHONE']):
                    p['ID'] = btx_contact['PHONE'][i]['ID']

                for i, p in enumerate(client['EMAIL']):
                    p['ID'] = btx_contact['EMAIL'][i]['ID']

                client['ID'] = btx_contact['ID']
                to_update.append(client)

            bitrix_contacts.remove(btx_contact)
        else:
            to_add.append(client)

    for old_deal in bitrix_contacts:
        to_remove.append(old_deal['ID'])

    return to_add, to_update, to_remove
コード例 #9
0
def run_bitrix():
    logging.info('Uploading bitrix data...')
    db = MySQL(host=Cfg.get('db_host'),
               port=int(Cfg.get('db_port')),
               user=Cfg.get('db_user'),
               password=Cfg.get('db_password'),
               db=Cfg.get('db_name'))
    db_data = get_db_data(db, Cfg.get('db_tables'), charset='utf8')

    rentals = get_products_from_db(db_data)
    to_add, to_update, to_delete = prepare_products(rentals)
    upload_products(to_add, to_update, to_delete)

    clients = get_clients_from_db(db_data)
    to_add, to_update, to_delete = prepare_contacts(clients)
    upload_contacts(to_add, to_update, to_delete)

    deals = get_deals_from_db(db_data)
    to_add, to_update, to_delete = prepare_deals(deals)
    upload_deals(to_add, to_update, to_delete)
コード例 #10
0
def run_bookingsync():
    t_total = time.time()
    logging.info('Obtaining data from bookingsync...')

    t_bfe = time.time()
    bookings_fee = advanced_request('bookings_fee',
                                    params={
                                        'from': '20111101',
                                        'status':
                                        'booked,unavailable,tentative'
                                    })
    logging.info('Obtained Bookings fee data in {} sec'.format(time.time() -
                                                               t_bfe))

    t_bkg = time.time()
    bookings = advanced_request('booking',
                                params={
                                    'from': '20111101',
                                    'status': 'booked,unavailable,tentative',
                                    'include_canceled': True
                                })
    logging.info('Obtained Bookings data in {} sec'.format(time.time() -
                                                           t_bkg))

    t_cl = time.time()
    clients = advanced_request('client', params={'from': '20111101'})
    logging.info('Obtained Clients data in {} sec'.format(time.time() - t_cl))

    t_ren = time.time()
    rentals = advanced_request('rental', params={'from': '20111101'})
    logging.info('Obtained Rentals data in {} sec'.format(time.time() - t_ren))

    t_prc = time.time()
    data = {
        'clients': get_clients(clients),
        'rentals': get_rentals(rentals),
        'bookings': get_bookings(bookings),
        'bookings_fee': get_bookings_fee(bookings_fee)
    }

    data['bookings_split'] = get_bookings_splitted(data['bookings_fee'],
                                                   data['bookings'],
                                                   data['rentals'])

    for b in data['bookings']:
        if b['client_id'] and not find_dict_in_list(data['clients'], 'id',
                                                    b['client_id']):
            # logging.info('Invalid foreign key client_id {}'.format(b['client_id']))
            b['client_id'] = None

        if b['rental_id'] and not find_dict_in_list(data['rentals'], 'id',
                                                    b['rental_id']):
            # logging.info('Invalid foreign key renal_id {}'.format(b['rental_id']))
            b['rental_id'] = None

    for bf in data['bookings_fee']:
        if bf['booking_id'] and not find_dict_in_list(data['bookings'], 'id',
                                                      bf['booking_id']):
            # logging.info('Invalid foreign key booking_id {}'.format(bf['booking_id']))
            bf['booking_id'] = None

    logging.info('Processed obtained data in {} sec'.format(time.time() -
                                                            t_prc))
    logging.info('Completed in {} second.'.format(time.time() - t_total))

    db = MySQL(host=Cfg.get('db_host'),
               port=int(Cfg.get('db_port')),
               user=Cfg.get('db_user'),
               password=Cfg.get('db_password'),
               db=Cfg.get('db_name'))

    write_data_to_db(db, data, Cfg.get('db_tables'))
コード例 #11
0
def get_bookings(bookings):
    my_bookings = []

    t_ren = time.time()
    sources = advanced_request('source',
                               params={
                                   'from': '20111101',
                                   'fields': 'id,name'
                               })
    logging.info('Obtained Sources data in {} sec'.format(time.time() - t_ren))

    t_ren = time.time()
    comments = advanced_request('booking_comment',
                                params={
                                    'from': '20111101',
                                    'fields': 'id,content'
                                })
    logging.info('Obtained Comments data in {} sec'.format(time.time() -
                                                           t_ren))

    t_ren = time.time()
    accounts = request_data(Cfg.get('bks_accounts_base_url'),
                            params={'fields': 'id,business_name'})
    logging.info('Obtained Accounts data in {} sec'.format(time.time() -
                                                           t_ren))

    for b in bookings:
        if b['status'] == 'Canceled':
            if (to_datetime(b['start_at']).date() -
                    to_datetime(b['canceled_at']).date()
                ).days > Cfg.get('btx_payed_status_interval'):
                continue

        my_booking = {
            'id':
            int(b['id']),
            'client_id':
            to_int(b['links']['client']),
            'rental_id':
            to_int(b['links']['rental']),
            'start_at':
            to_datetime(b['start_at']),
            'end_at':
            to_datetime(b['end_at']),
            'created_at':
            to_datetime(b['created_at']),
            'canceled_at':
            to_datetime(b['canceled_at']),
            'balance_due_at':
            to_datetime(b['balance_due_at']),
            'tentative_expires_at':
            to_datetime(b['tentative_expires_at']),
            'updated_at':
            to_datetime(b['updated_at']),
            'contract_updated_at':
            to_datetime(b['contract_updated_at']),
            'status':
            b['status'],
            'reference':
            b['reference'],
            'booked':
            b['booked'],
            'unavailable':
            b['unavailable'],
            'initial_price':
            to_float(b['initial_price']),
            'initial_rental_price':
            to_float(b['initial_rental_price']),
            'channel_price':
            to_float(b['channel_price']),
            'discount':
            b['discount'],
            'final_rental_price':
            to_float(b['final_rental_price']),
            'final_price':
            to_float(b['final_price']),
            'paid_amount':
            to_float(b['paid_amount']),
            'currency':
            b['currency'],
            'notes':
            b['notes'],
            'damage_deposit':
            to_float(b['damage_deposit']),
            'charge_damage_deposit_on_arrival':
            to_float(b['charge_damage_deposit_on_arrival']),
            'adults':
            to_int(b['adults']),
            'children':
            to_int(b['children']),
            'bookings_payments_count':
            to_int(b['bookings_payments_count']),
            'review_requests_count':
            to_int(b['review_requests_count']),
            'locked':
            b['locked'],
            'cancelation_reason':
            b['cancelation_reason'],
            'expected_checkin_time':
            b['expected_checkin_time'],
            'expected_checkout_time':
            b['expected_checkout_time'],
            'payment_url':
            b['payment_url'],
            'rental_payback_to_owner':
            to_float(b['rental_payback_to_owner']),
            'final_payback_to_owner':
            to_float(b['final_payback_to_owner']),
            'commission':
            to_float(b['commission']),
            'door_key_code':
            b['door_key_code'],
            'payment_left_to_collect':
            to_float(b['payment_left_to_collect']),
            'owned_by_app':
            b['owned_by_app'],
            'account_id':
            to_int(b['links']['account']),
            'probability_win':
            None,
            'source':
            b['links']['source'] if b['links']['source'] else 'Praguestars.com'
        }

        if my_booking['source']:
            source = find_dict_in_list(sources, 'id', my_booking['source'])
            if source:
                my_booking['source'] = source['name']

        if my_booking['start_at']:
            days_interval = (my_booking['start_at'] - datetime.now()).days
            my_booking['probability_win'] = to_int(
                Cfg.get_interval_prob(days_interval))

        # get comments
        comment_str = ''
        for comment_id in b['links']['booking_comments']:
            comment = find_dict_in_list(comments, 'id', comment_id)
            if comment:
                comment_str += comment['content'] + '\n'
        my_booking['comments'] = comment_str

        my_bookings.append(my_booking)

    # get account name
    for b in my_bookings:
        for a in accounts['accounts']:
            if len(a) > 0 and a['id'] == b['account_id']:
                b['account'] = a['business_name']

    return my_bookings
コード例 #12
0
from bookingsync_utils import *
from mysql_wrapper import MySQL
from utilities import Cfg
from utilities import find_all_dicts_in_list
from utilities import find_dict_in_list
from utilities import is_number
from utilities import to_float
from utilities import to_int
from utilities import write_data_to_db

dir_path = os.path.dirname(os.path.realpath(__file__))

sys.path.append(os.path.join(dir_path, "drivers"))

_json_file = dir_path + os.sep + '..' + os.sep + Cfg.get('bks_token_file')
_client_id = Cfg.get('bks_client_id')
_client_secret = Cfg.get('bks_client_secret')
_redirect_uri = Cfg.get('bks_redirect_uri')
_native_date_format = '%Y-%m-%dT%H:%M:%SZ'

with open(_json_file, 'r') as f:
    _token = json.load(f)


def update_token():
    global _token
    req = requests.post('https://www.bookingsync.com/oauth/token',
                        params={
                            'client_id': _client_id,
                            'client_secret': _client_secret,
コード例 #13
0
import time
from datetime import datetime
from datetime import date
from multidimensional_urlencode import urlencode

import requests
import tqdm

from mysql_wrapper import MySQL
from utilities import Cfg
from utilities import find_dict_in_list
from utilities import get_db_data

dir_path = os.path.dirname(os.path.realpath(__file__))

_json_file = dir_path + os.sep + '..' + os.sep + Cfg.get('btx_token_file')
_client_id = Cfg.get('btx_client_id')
_client_secret = Cfg.get('btx_client_secret')
_redirect_uri = 'blabla'
_main_url = 'https://praguestars.bitrix24.com/rest/METHOD'

_contact_fields = 'crm.contact.fields'
_contact_list = 'crm.contact.list'
_contact_remove = 'crm.contact.delete'
_contact_update = 'crm.contact.update'
_contact_add = 'crm.contact.add'

_deal_add_contact = 'crm.deal.contact.add'
_deal_add_product = 'crm.deal.productrows.set'
_deal_fields = 'crm.deal.fields'
_deal_list = 'crm.deal.list'
コード例 #14
0
from datetime import timedelta
from utilities import Cfg
import logging
import re
from utilities import to_float

fee_names = Cfg.get('fee_mapping')
a_day = timedelta(days=1)


def is_same_month(end, start): return start.month == end.month and start.year == end.year


def get_fee_name(fee):
    for loc in fee['name'].keys():
        if fee['name'][loc]:
            try:
                return fee_names[fee['name'][loc].lower()]
            except (KeyError, ValueError):
                continue

    logging.warning('No tax name in: '.format(fee))
    return ''


def get_fees_for_splitted_booking(booking_split, fees, bkg, portion=1):
    # initialize fee fields
    for fee_name in set(fee_names.values()):
        booking_split[fee_name] = ''

    # try to get fee info from booking comments, as some booking_fee data is not available via api