-- Autogenerated with DRAKON Editor 1.32
require('strict').on()

local table = table
local string = string
local pairs = pairs
local ipairs = ipairs
local io = io
local pcall = pcall
local xpcall = xpcall
local debug = debug
local tostring = tostring
local type = type
local clock = require("clock")
local log = require("log")
local digest = require("digest")
local fiber = require("fiber")
local json = require("json")
local fio = require("fio")
local math = require("math")
local os = os
local error = error
local print = print

local utf8 = require("lua-utf8")

local utils = require("utils")
local ej = require("ej")
local soap = require("soap")

local xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"

-- configuration
local global_cfg = global_cfg
local price_cfg = price_cfg
local external_creds = external_creds


setfenv(1, {}) 

local module = nil

function add_property(obj, name, value)
    -- item 23
    local container = {
    	tag = name,
    	value
    }
    -- item 24
    table.insert(obj, container)
end

function autopay(details, user_id)
    -- item 377
    local method_name = "AutoPay3"
    -- item 373
    local success, result
    -- item 368
    local payex_account = external_creds.payex_account
    -- item 381
    local price = price_to_long(details.total)
    local agreement_id = details.agreement_id
    -- item 366
    local props = {}
    -- item 367
    add_property(props, "accountNumber", payex_account)
    add_property(props, "agreementRef", details.agreement_ref)
    add_property(props, "price", price)
    
    add_property(props, "productNumber", details.product_code)
    add_property(props, "description", details.product_pay_name)
    add_property(props, "orderId", agreement_id)
    
    add_property(props, "purchaseOperation", "SALE")
    add_property(props, "currency", details.currency)
    -- item 370
    local hash = make_hash_autopay(props)
    -- item 369
    add_property(props, "hash", hash)
    -- item 374
    local ok, parsed = call_payex(
    	method_name,
    	user_id,
    	props,
    	agreement_id,
    	{
    		"code",
    		"description",
    		"errorCode",
    		"paramName",
    		"thirdPartyError",
    		"thirdPartySubError",
    		"transactionNumber",
    		"paymentMethod"
    	}
    )
    -- item 375
    if ok then
        -- item 409
        if (parsed.errorCode == "OK") and (parsed.description == "OK") then
            -- item 414
            log_success(
            	method_name,
            	user_id,
            	agreement_id
            )
            -- item 407
            success = true
            result = {
            	trans_number = parsed.transactionNumber,
            	method = parsed.paymentMethod
            }
        else
            -- item 415
            log_error_payex(
            	method_name,
            	user_id,
            	agreement_id,
            	parsed
            )
            -- item 416
            success = false
            result = "ERR_AUTOPAY"
        end
    else
        -- item 419
        success = false
        result = "ERR_AUTOPAY"
    end
    -- item 490
    return success, result
end

function call_payex(method, user_id, props, agreement_id, out_props)
    -- item 432
    return call_payex_core(
    	method,
    	user_id,
    	props,
    	agreement_id,
    	out_props
    )
end

function call_payex_core(method_name, user_id, props, agreement_id, out_props)
    -- item 496
    local message
    -- item 517
    local ns, url = get_call_info(method_name)
    -- item 191
    local soap_payload = {
    	method = method_name,
    	namespace = ns,
    	entries = props
    }
    -- item 192
    local xml = soap.encode(soap_payload)
    xml = xml_header .. xml
    -- item 194
    local body = {
    	url = url,
    	data = xml,
    	headers = {},
    	mime = "text/xml; charset=utf-8"
    }
    -- item 400
    log_call(
    	method_name,
    	user_id,
    	agreement_id
    )
    -- item 195
    local call_result = utils.msgpack_call(
    	"localhost",
    	global_cfg.https_sender_port,
    	body
    )
    -- item 491
    if call_result then
        -- item 199
        if utils.is_empty(call_result.error) then
            -- item 196
            local method, ns, results
             = soap.decode(call_result)
            -- item 197
            local result = results[1][1]
            -- item 386
            local ok, parsed = utils.parse_xml(
            	out_props,
            	result
            )
            -- item 387
            if ok then
                -- item 198
                return true, parsed
            else
                -- item 389
                log_error_parse(
                	method_name,
                	user_id,
                	agreement_id,
                	parsed
                )
                -- item 398
                return false, parsed
            end
        else
            -- item 495
            message = call_result.error
            -- item 397
            log_error_call(
            	method_name,
            	user_id,
            	agreement_id,
            	message
            )
            -- item 202
            return false, message
        end
    else
        -- item 492
        message = "web service call failed"
        -- item 397
        log_error_call(
        	method_name,
        	user_id,
        	agreement_id,
        	message
        )
        -- item 202
        return false, message
    end
end

function complete(agreement_id, order_ref, user_id)
    -- item 365
    local method_name = "Complete"
    -- item 162
    local success, result
    -- item 133
    local payex_account = external_creds.payex_account
    -- item 130
    local props = {}
    -- item 131
    add_property(props, "accountNumber", payex_account)
    add_property(props, "orderRef", order_ref)
    -- item 135
    local hash = make_hash_complete(props)
    -- item 134
    add_property(props, "hash", hash)
    -- item 215
    local ok, parsed = call_payex(
    	method_name,
    	user_id,
    	props,
    	agreement_id,
    	{
    		"errorCode",
    		"description",
    		"paramName",
    		"errorCodeSimple",
    		"transactionStatus",
    		"transactionNumber",
    		"transactionErrorCode",
    		"transactionErrorDescription",
    		"transactionThirdPartyError",
    		"paymentMethod",
    		"paymentMethodExpireDate"
    	}
    )
    -- item 216
    if ok then
        -- item 156
        if ((parsed.errorCode == "OK") and (parsed.description == "OK")) and (is_status_ok(parsed.transactionStatus)) then
            -- item 363
            log_success(
            	method_name,
            	user_id,
            	agreement_id
            )
            -- item 148
            success = true
            result = {
            	trans_number = parsed.transactionNumber,
            	method = parsed.paymentMethod,
            	expiry = parsed.paymentMethodExpireDate
            }
        else
            -- item 364
            log_error_payex(
            	method_name,
            	user_id,
            	agreement_id,
            	parsed
            )
            -- item 154
            success = false
            result = "ERR_COMPLETE_PAYMENT"
        end
    else
        -- item 406
        success = false
        result = "ERR_COMPLETE_PAYMENT"
    end
    -- item 221
    return success, result
end

function create_agreement(details, agreement_id, user_id)
    -- item 279
    local success, result
    -- item 278
    local payex_account = external_creds.payex_account
    -- item 280
    local max_amount = math.floor(
    	details.total * 300
    )
    -- item 349
    local method_name = "CreateAgreement3"
    -- item 276
    local props = {}
    -- item 277
    add_property(props, "accountNumber", payex_account)
    add_property(props, "merchantRef", details.product_code)
    add_property(props, "description", details.product_pay_name)
    add_property(props, "purchaseOperation", "SALE")
    add_property(props, "maxAmount", max_amount)
    add_property(props, "notifyUrl", "")
    add_property(props, "startDate", "")
    add_property(props, "stopDate", "")
    -- item 289
    local hash = make_hash_ca(props)
    -- item 288
    add_property(props, "hash", hash)
    -- item 294
    local ok, parsed = call_payex(
    	method_name,
    	user_id,
    	props,
    	agreement_id,
    	{
    		"errorCode",
    		"description",
    		"paramName",
    		"thirdPartyError",
    		"agreementRef",
    	}
    )
    -- item 295
    if ok then
        -- item 309
        if (parsed.errorCode == "OK") and (parsed.description == "OK") then
            -- item 352
            log_success(
            	method_name,
            	user_id,
            	agreement_id
            )
            -- item 301
            success = true
            result = {
            	agreement_ref = parsed.agreementRef
            }
        else
            -- item 353
            log_error_payex(
            	method_name,
            	user_id,
            	agreement_id,
            	parsed
            )
            -- item 308
            success = false
            result = "ERR_CREATE_PAYMENT"
        end
    else
        -- item 405
        success = false
        result = "ERR_CREATE_PAYMENT"
    end
    -- item 434
    return success, result
end

function delete_agreement(agreement_ref, user_id, agreement_id)
    -- item 455
    local method_name = "DeleteAgreement"
    -- item 454
    local success, result
    -- item 451
    local payex_account = external_creds.payex_account
    -- item 449
    local props = {}
    -- item 450
    add_property(props, "accountNumber", payex_account)
    add_property(props, "agreementRef", agreement_ref)
    -- item 453
    local hash = make_hash_delete(props)
    -- item 452
    add_property(props, "hash", hash)
    -- item 465
    local ok, parsed = call_payex(
    	method_name,
    	user_id,
    	props,
    	agreement_id,
    	{
    		"errorCode",
    		"description",
    		"paramName"
    	}
    )
    -- item 466
    if ok then
        -- item 475
        if (parsed.errorCode == "OK") and (parsed.description == "OK") then
            -- item 479
            log_success(
            	method_name,
            	user_id,
            	agreement_id
            )
            -- item 472
            success = true
            result = {}
        else
            -- item 480
            log_error_payex(
            	method_name,
            	user_id,
            	agreement_id,
            	parsed
            )
            -- item 474
            success = false
            result = "ERR_COMPLETE_PAYMENT"
        end
    else
        -- item 469
        success = false
        result = "ERR_DELETE_AGREEMENT"
    end
    -- item 482
    return success, result
end

function get_call_info(method_name)
    -- item 515
    local ns, url
    -- item 5020001
    if ((method_name == "CreateAgreement3") or (method_name == "DeleteAgreement")) or (method_name == "AutoPay3") then
        -- item 513
        ns = "http://external.payex.com/PxAgreement/"
        url = external_creds.payex_agreement
    else
        -- item 514
        ns = "http://external.payex.com/PxOrder/"
        url = external_creds.payex_order
    end
    -- item 516
    return ns, url
end

function get_property(obj, name)
    for _, element in ipairs(obj) do
        -- item 45
        if (type(element) == "table") and (element.tag == name) then
            -- item 51
            local value = element[1] or ""
            -- item 53
            return tostring(value)
        end
    end
    -- item 52
    error("Property not found: " .. name)
end

function initialize(payment, user_id)
    -- item 359
    local method_name = "Initialize8"
    -- item 106
    local success, result
    -- item 6
    ej.info("payex_initialize", payment)
    -- item 26
    local returnUrl = global_cfg.my_site
     .. "/buy?action=completed"
    -- item 27
    local cancelUrl = global_cfg.my_site
     .. "/buy?action=cancel"
    -- item 28
    local price = price_to_long(payment.total)
    -- item 34
    local payex_account = external_creds.payex_account
    -- item 242
    local mva = math.floor(price_cfg.mva * 10000)
    -- item 246
    local agreement_ref = payment.agreement_ref or ""
    local agreement_id = payment.agreement_id
    -- item 10
    local props = {}
    -- item 11
    add_property(props, "accountNumber", payex_account)
    add_property(props, "purchaseOperation", "SALE")
    add_property(props, "price", price)
    add_property(props, "priceArgList", "")
    add_property(props, "currency", payment.currency)
    add_property(props, "vat", mva)
    -- item 25
    add_property(props, "orderID", agreement_id)
    add_property(props, "productNumber", payment.product_code)
    add_property(props, "description", payment.product_pay_name)
    
    add_property(props, "clientIPAddress", payment.ip)
    add_property(props, "clientIdentifier", "")
    add_property(props, "additionalValues", "RESPONSIVE=1")
    add_property(props, "externalID", "")
    add_property(props, "returnUrl", returnUrl)
    
    add_property(props, "view", "CREDITCARD")
    add_property(props, "agreementRef", agreement_ref)
    add_property(props, "cancelUrl", cancelUrl)
    add_property(props, "clientLanguage", payment.language)
    -- item 37
    local hash = make_hash_initialize(props)
    -- item 36
    add_property(props, "hash", hash)
    -- item 203
    local ok, parsed = call_payex(
    	method_name,
    	user_id,
    	props,
    	agreement_id,
    	{
    		"errorCode",
    		"description",
    		"paramName",
    		"thirdPartyError",
    		"orderRef",
    		"redirectUrl"
    	}
    )
    -- item 103
    if ok then
        -- item 109
        if (parsed.errorCode == "OK") and (parsed.description == "OK") then
            -- item 357
            log_success(
            	method_name,
            	user_id,
            	agreement_id
            )
            -- item 94
            success = true
            result = {
            	order_ref = parsed.orderRef,
            	redirect = parsed.redirectUrl
            }
        else
            -- item 358
            log_error_payex(
            	method_name,
            	user_id,
            	agreement_id,
            	parsed
            )
            -- item 404
            success = false
            result = "ERR_CREATE_PAYMENT"
        end
    else
        -- item 107
        success = false
        result = "ERR_CREATE_PAYMENT"
    end
    -- item 8
    return success, result
end

function is_status_ok(status)
    local _sw2270000_ = 0
    -- item 2270000
    _sw2270000_ = tostring(status)
    -- item 2270001
    if _sw2270000_ == "0" then
        -- item 238
        return true
    else
        -- item 239
        return false
    end
end

function log_call(method_name, user_id, trans_id)
    -- item 346
    ej.info(
      "payex_call",
      {
        method_name = method_name,
        trans_id = trans_id,
        user_id = user_id
      }
    )
end

function log_error_call(method_name, user_id, trans_id, details)
    -- item 340
    ej.info(
      "payex_call_error",
      {
        method_name = method_name,
        trans_id = trans_id,
        details = details,
        user_id = user_id
      }
    )
end

function log_error_parse(method_name, user_id, trans_id, details)
    -- item 339
    ej.info(
      "payex_xml_error",
      {
        method_name = method_name,
        trans_id = trans_id,
        details = details,
        user_id = user_id
      }
    )
end

function log_error_payex(method_name, user_id, trans_id, details)
    -- item 338
    ej.info(
      "payex_error",
      {
        method_name = method_name,
        trans_id = trans_id,
        details = details,
        user_id = user_id
      }
    )
end

function log_success(method_name, user_id, trans_id)
    -- item 347
    ej.info(
      "payex_success",
      {
        method_name = method_name,
        user_id = user_id,
        trans_id = trans_id
      }
    )
end

function make_hash(payment, hashed)
    -- item 35
    local payex_key = external_creds.payex_key
    -- item 55
    local acc = ""
    for _, name in ipairs(hashed) do
        -- item 58
        local value = get_property(payment, name)
        -- item 59
        acc = acc .. value
    end
    -- item 60
    acc = acc .. payex_key
    -- item 62
    local hash = digest.md5_hex(acc)
    -- item 115
    return hash
end

function make_hash_autopay(payment)
    -- item 488
    local hashed = {
      "accountNumber",
      "agreementRef",
      "price",
      "productNumber",
      "description",
      "orderId",
      "purchaseOperation",
      "currency"
    }
    -- item 489
    return make_hash(payment, hashed)
end

function make_hash_ca(payment)
    -- item 286
    local hashed = {
    "accountNumber",
    "merchantRef",
    "description",
    "purchaseOperation",
    "maxAmount",
    "notifyUrl",
    "startDate",
    "stopDate"
    }
    -- item 287
    return make_hash(payment, hashed)
end

function make_hash_complete(payment)
    -- item 184
    local hashed = {
      "accountNumber",
      "orderRef"
    }
    -- item 185
    return make_hash(payment, hashed)
end

function make_hash_delete(payment)
    -- item 461
    local hashed = {
      "accountNumber",
      "agreementRef"
    }
    -- item 462
    return make_hash(payment, hashed)
end

function make_hash_initialize(payment)
    -- item 169
    local hashed = {
    "accountNumber",
    "purchaseOperation",
    "price",
    "priceArgList",
    "currency",
    "vat",
    "orderID",
    "productNumber",
    "description",
    "clientIPAddress",
    "clientIdentifier",
    "additionalValues",
    "externalID",
    "returnUrl",
    "view",
    "agreementRef",
    "cancelUrl",
    "clientLanguage"
    }
    -- item 178
    return make_hash(payment, hashed)
end

function price_to_long(amount)
    -- item 17
    return utils.round(amount * 100, 0)
end

function replace_call_payex(injected)
    -- item 427
    call_payex_core = injected
end


module = {
	initialize = initialize,
	complete = complete,
	autopay = autopay,
	create_agreement = create_agreement,
	replace_call_payex = replace_call_payex,
	delete_agreement = delete_agreement
}

return module
