vendor.py 8.98 KB
"""
Module proses:
Save
Invoice To Vendor
Invoice To Customer
"""

import hashlib
import json
import re
from datetime import datetime
from importlib import import_module

import colander
import requests
import xmltodict
from deform import widget, Form, ValidationFailure
# from opensipkd.pasar.models import PartnerLog
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config

from . import BaseView  # , save_file_upload
from ..models import (DBSession, flush_row, Partner, PartnerProduk, H2hArInvoiceDet)
from ..models import (Produk, ProdukKategori)
from ..tools import (btn_next, date_from_str, get_settings, btn_reset,
                     btn_inquiry, btn_advice, btn_payment, get_jsonrpc)

from ..tools import log


class VendorClass(object):
    def __init__(self, vendor_produk, invoice_det, **kwargs):
        """
        :param vendor_produk:
        :param bill_no:
        :param customer_id:
        :param cust_trx:
        :param row:
        """
        self.vendor_produk = vendor_produk
        self.invoice_det = invoice_det
        self.v_produk_kd = vendor_produk.kode
        self.kategori = vendor_produk.produk.kategori.kode
        self.id_pel = invoice_det and invoice_det.id_pel or None
        self.request = None
        self.response = None
        self.result = None
        self.vend_inv_no = invoice_det and invoice_det.vend_inv_no or None
        self.status = invoice_det and invoice_det.status or 0

        self.serial_number = invoice_det and hasattr(invoice_det, 'serial_number') \
                             and invoice_det.serial_number or None
        self.amt_buy = 0

    def save_log(self, typ):
        # if not self.partner_log:
        # row = self.partner_log or PartnerLog()
        # row.vendor_id = self.vendor_id
        # row.produk_id = self.produk_id
        # row.bill_no = self.bill_no
        # row.customer_id = self.customer_id
        #
        # row.cust_trx = self.cust_trx
        # row.vend_trx = self.vend_trx
        # row.status = self.status
        # row.amt_buy = self.amt_buy
        # row.amt_sell = self.amt_sell
        self.invoice_det.status = self.status
        if hasattr(self.invoice_det, 'serial_number'):
            self.invoice_det.serial_number = self.serial_number

        if self.vend_inv_no:
            self.invoice_det.vend_inv_no = self.vend_inv_no

        if self.amt_buy:
            self.invoice_det.amt_buy = self.amt_buy

        if typ == 'inquiry':
            self.invoice_det.inquiry = dict(request=self.request,
                                            response=self.response,
                                            result=self.result)
        elif typ == 'payment':
            self.invoice_det.payment = dict(request=self.request,
                                            response=self.response,
                                            result=self.result)
        elif typ == 'advice':
            self.invoice_det.advice = dict(request=self.request,
                                           response=self.response,
                                           result=self.result)
        elif typ == 'info':
            self.invoice_det.info = dict(request=self.request,
                                         response=self.response,
                                         result=self.result)

        flush_row(self.invoice_det)


class Other(object):
    def __init_subclass__(self, **kwargs):
        self.settings = get_settings()
        vendor_produk = "vendor_produk" in kwargs and kwargs["vendor_produk"] or None
        self.vendor_id = vendor_produk.partner_id
        self.produk_id = vendor_produk.produk_id
        self.v_produk_kd = vendor_produk.kode
        self.produk_kd = vendor_produk.produk.kode
        self.kategori = vendor_produk.produk.kategori.nama
        values = "values" in kwargs and kwargs["values"] or None
        # self.bill_no = bill_no
        self.customer_id = 'customer_id' in values and values['customer_id'] or None
        self.cust_trx = 'cust_trx' in values and values['cust_trx'] or None
        row = 'row' in values and values['row'] or None
        self.partner_log = row
        self.partner_log_id = row and row.id or None

        self.status = row and row.status or 0
        self.amt_buy = row and row.amt_buy or 0
        self.amt_sell = row and row.amt_sell or 0
        self.cust_trx = row and row.cust_trx or ""
        self.vend_trx = row and row.vend_trx or ""

        self.response = None
        self.request = None

    #     bill_no, customer_id = customer_id,
    #     cust_trx_id = cust_trx_id, row = row,
    #

    def get_product(self):
        pass

    def inquiry(self):
        pass

    def payment(self):
        pass


def sha256(hash_string):
    return hashlib.sha256(hash_string.encode()).hexdigest()


def update_harga(p, k, v):
    row = PartnerProduk.query() \
        .filter_by(kode=k, partner_id=p.id).first()
    if not row:
        row = PartnerProduk()
        row.kode = k
        row.partner_id = p.id
        row.created = datetime.now()
    else:
        row.updated = datetime.now()

    row.harga = v
    flush_row(row)
    return True


def proses_odeo(data):
    settings = get_settings()
    mid = 'odeo_mid' in settings and settings["odeo_mid"] or None
    key = 'odeo_key' in settings and settings["odeo_key"] or None
    partner = Partner.query_kode("ODEO").first()
    status = str(data["status"])
    if status == "BROADCAST_NEW_PRICE":
        signature = sha256("{mid}{key}{status}".format(
            mid=mid, key=key, status=status))

        if signature != data["signature"]:
            log.info("Signature Vendor Different")
            log.info("local %s, vendor %s" % (signature, data["signature"]))
            return dict(error="Signature different")

        new_price = data["new_prices"]
        for k in new_price:
            v = new_price[k]
            update_harga(partner, k, v)
        return dict(success=True)

    else:
        order_id = str(data["order_id"])
        signature = sha256("{order_id}{mid}{key}{status}".format(
            order_id=order_id, mid=mid, key=key, status=status))
        if signature != data["signature"]:
            log.info("Signature Vendor Different")
            log.info("local %s, vendor %s" % (signature, data["signature"]))
            return dict(error="Signature Different")
        order = H2hArInvoiceDet.query() \
            .filter(H2hArInvoiceDet.vendor_id == partner.id,
                    H2hArInvoiceDet.vend_inv_no == str(order_id)).first()

        if order:
            if status == "COMPLETED":
                order.status = 1
            else:
                order.status = -2
            order.notify = dict(post=data)
            if "sn" in data and data["sn"]:
                order.serial_number = data["sn"]
            flush_row(order)
            # todo: add to customer notify table
            # todo: create cron for notify
            # proses jika status 1 notify ada isinya tapi belum ada field result
            # todo: create cron torecurring order to other vendor
            # jika status = -2 proses vendor yang lain
            callback_merchant(order)
            return order


def callback_merchant(order):
    # Callback to merchant
    invoice = order.invoice
    customer = invoice.customer

    if customer and customer.website:
        url = customer.website
        users = customer.users
        status = order.status == 1 and "SUCCESS" \
                 or order.status > -2 and "FAILED" \
                 or "PENDING"
        key = invoice.cust_inv_no + users.user_name + users.api_key + status
        signature = sha256(key.encode()).decode()
        data = produk = []
        dat = dict(
            invoice_no=invoice.cust_inv_no,
            signature=signature)
        produk.append(dict(
            denom=order.produk.kode,
            id_pel=order.id_pel,
            subtotal=order.amt_sell + order.discount,
            discount=order.discount,
            total=order.amt_sell,
            status=status,
            serial_number=order.serial_number
        ))
        dat.update(produk=produk)
        data.append(dat)
        js = get_jsonrpc(method="notify", params=data)
        log.info("Notify: %s %s" %(url, js))
        with requests.session():
            requests.post(url, data=data, timeout=15)


@view_config(route_name='api-vendor-notify', renderer='json')
def api_vendor_notify(request):
    vendor_nm = request.matchdict['name']
    if vendor_nm == "odeo":
        data = json.loads(request.text)
        order = proses_odeo(data)


@view_config(route_name='api-vendor-test', renderer="string")
def vendor_test(request):
    params = request.params
    vendor = request.matchdict['vendor']
    result = dict(a=1)
    request.response.content_type = "text / xml"
    if vendor == "vsi":
        controls = request.GET.items()
        params = dict(controls)
        params["status"] = "SUCCESS"
        result = dict(root=params)
        result = xmltodict.unparse(result)

    elif vendor == "odeo":
        params = json.loads(request.text)
        result = request.text
    return result