vendor.py 11.8 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.settings = get_settings()
        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

        # tambahan by tatang
        self.row_invoice = invoice_det and invoice_det.h2h_ar_invoice or None
        self.row_customer = self.row_invoice and self.row_invoice.customer or None

    def set_response(self, data=None, message=None, code=999, typ="inquiry"):
        if not data and message:
            message = message and message or "Biller No Response"
            data = dict(code=code,
                         message=message)

        self.result = data
        self.save_log(typ)
        log.info("Result: %s" % data)
        return data

    def set_success(self, data=None):
        self.status = 1
        typ = "payment"
        data = data and data or {}
        data.update(dict(code=0,
                         message="SUCCESS",
                         status="SUCCESS"))
        return self.set_response(data, typ=typ)

    def set_failed(self, data=None, message=None):
        typ = "payment"
        self.status = -3
        data = data and data or {}
        message = message and message or "FAILED"
        data.update(dict(code=13,
                         message=message,
                         status="FAILED"))
        return self.set_response(data, typ=typ)

    def set_double(self, data=None, message=None):
        self.status = -3
        typ = "payment"
        message = message and message or "DOUBLE"
        data = data and data or {}
        data.update(dict(code=67,
                         message=message,
                         status="FAILED"))
        return self.set_response(data, typ=typ)

    def set_pending(self, data=None, message=None):
        data = data and data or {}
        typ = "payment"
        message = message and message or "PENDING"
        data.update(dict(code=68,
                         status="PENDING",
                         message=message)
                    )
        return self.set_response(data, typ=typ)

    def get_price(self):
        product_id = self.invoice_det.produk.id
        if hasattr(self.invoice_det, "customer_id"):
            partner_id = self.invoice_det.customer_id
        else:
            partner_id = self.invoice_det.h2h_ar_invoice.customer_id

        harga = self.vendor_produk.produk.harga
        self.discount = PartnerProduk.get_discount(partner_id, product_id)
        self.amt_sell = harga - self.discount
        return dict(
            subtotal=int(harga),
            discount=int(self.discount),
            total=int(self.amt_sell)
        )

    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 = -3
            order.notify = dict(post=data)
            if "sn" in data and data["sn"]:
                order.serial_number = data["sn"]
            else:
                message = 'message' in data and data["message"] or ""
                if message:
                    loc = message.find("SN: ")
                    if loc>-1:
                        sn = message[loc+4:loc+28]
                        order.serial_number=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)
        data = []
        produk = []
        dat = dict(
            invoice_no=invoice.cust_inv_no,
            signature=signature)

        discount = order.discount and order.discount or 0
        produk.append(dict(
            denom=order.produk.kode,
            id_pel=order.id_pel,
            subtotal=order.amt_sell + discount,
            discount=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=dict(data=data))
        log.info("Notify: %s %s" %(url, js))
        try:
            with requests.session():
                requests.post(url, data=data, timeout=10)
        except:
            pass


@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