diff --git a/CHANGELOG.md b/CHANGELOG.md index fd819b3..9b68ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -- First testing version of pmtservice for Xero accounting is running - ### Added - Added new service for Xero integration @@ -20,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added - Convenience buttons on checkout for wallets that are not ZIP-321-compliant +- PmtService Component first alpha version ready for testing ### Fixed diff --git a/src/app/invoice/invoice.component.ts b/src/app/invoice/invoice.component.ts index 75e91ed..85fbebc 100644 --- a/src/app/invoice/invoice.component.ts +++ b/src/app/invoice/invoice.component.ts @@ -66,6 +66,7 @@ export class InvoiceComponent implements OnInit { logoHeight: 50, correctLevel: QRCode.CorrectLevel.H }); + this.error = false; } else { this.error = true; this.codeString = 'Test'; diff --git a/src/app/pmtservice/pmtservice.component.css b/src/app/pmtservice/pmtservice.component.css index f018ed3..ef2d460 100644 --- a/src/app/pmtservice/pmtservice.component.css +++ b/src/app/pmtservice/pmtservice.component.css @@ -22,3 +22,90 @@ background: #ff5722; } +.invoiceDetail { + font-family: Roboto Mono !important; + padding: 10px; + max-width: 600px; +} + +.invoiceHdrTxt1 { + font-family: Spartan !important; + text-align: center; + font-size: 30px; + font-weight: 700; +} + +.invoiceHdrTxt2 { + font-family: Spartan !important; + text-align: center; + font-size: 16px; + font-weight: 400; +} + +.invoiceHdrTxt3 { + font-family: Spartan !important; + text-align: center; + font-size: 12px; + font-weight: 300; +} + +.detailTitle1 { + border-top: solid 2px; + border-bottom: solid 2px; + border-color: navy; + text-align: left; +} + +.detailTitle2 { + border-top: solid 2px; + border-bottom: solid 2px; + border-color: navy; + text-align: right; +} + +.detailLineRight { + border-top: solid 2px; + border-bottom: solid 2px; + border-color: navy; + text-align: right; +} + +.detailLineLeft { + border-top: solid 2px; + border-bottom: solid 2px; + border-color: navy; + text-align: right; +} + +.invoice-title { + font-size: 16px; + font-weight: 700; + background: lightcyan; + line-height: 30px; + padding: 5px; +} + +.invoice-detail { + line-height: 20px; + font-size: 16px; + font-weight: 400; + padding-top: 4px; + padding-bottom: 4px; +} + +.invoice-total { + margin-top: 40px; +} + +.qrcode { + display: flex; + float: right; +} + +.zecData { + width: auto; + font-family: Spartan !important; + font-size: 16px; + font-weight: 700; + text-align: right; +} diff --git a/src/app/pmtservice/pmtservice.component.html b/src/app/pmtservice/pmtservice.component.html index 9b2cb25..4f5e5d4 100644 --- a/src/app/pmtservice/pmtservice.component.html +++ b/src/app/pmtservice/pmtservice.component.html @@ -128,36 +128,100 @@
+
+
Invoice
+
Order ID: {{orderId}}
+
Date:{{order.timestamp | date}} +
+
+
Zcash Price: {{order.price | number: '1.02' | currency: order.currency.toUpperCase()}}
+
+
Total: {{order.totalZec | number: '1.08'}} +
+
+
+ + + + + + + + + + + + + + + + +
+ Item + + Qty. + + Price ({{order.currency.toUpperCase()}}) +
+ {{item.name}} + + {{item.qty}} + + {{( item.qty * item.cost ) | number : '1.02' | currency: order.currency.toUpperCase()}} +
+ Invoice Total: + -
-
-
-
- Invoice Goes here!!! -
-
-
- Payment request was not processed!! -
-
-
+
+ {{ order.total | currency: order.currency.toUpperCase()}} +
+
+ + + + + +
+

+  Payment confirmed

+

+  Payment pending!!

+
+
+
+
+
+ Scan the QR code with your wallet to make payment +
+ +
+
- \ No newline at end of file diff --git a/src/app/pmtservice/pmtservice.component.ts b/src/app/pmtservice/pmtservice.component.ts index a4569f0..25ff5ec 100644 --- a/src/app/pmtservice/pmtservice.component.ts +++ b/src/app/pmtservice/pmtservice.component.ts @@ -4,13 +4,15 @@ import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http"; import { PmtData } from "./pmtservice.model"; import { XeroInvoice } from "./xeroinvoice.model"; import { Owner } from '../owner.model'; -import { Item } from '../items/item.model' +// import { Item } from '../items/item.model' import { Order } from '../order/order.model' import { ConfigData } from '../configdata'; +import { faCheck, faHourglass } from '@fortawesome/free-solid-svg-icons'; +var QRCode = require('easyqrcodejs'); +var URLSafeBase64 = require('urlsafe-base64'); var Buffer = require('buffer/').Buffer; - @Component({ selector: 'app-pmtservice', templateUrl: './pmtservice.component.html', @@ -19,6 +21,9 @@ var Buffer = require('buffer/').Buffer; export class PmtserviceComponent implements OnInit { + faCheck = faCheck; + faHourglass = faHourglass; + beUrl = ConfigData.Be_URL; private reqHeaders: HttpHeaders = new HttpHeaders(); @@ -45,6 +50,7 @@ export class PmtserviceComponent implements OnInit { }; public owner: Owner = { + _id: '', address: '', name: '', currency: 'usd', @@ -69,12 +75,41 @@ export class PmtserviceComponent implements OnInit { payconf: false, viewkey: '' }; + +public order: Order = { + _id : '', + address: '', + session: '', + timestamp: '', + closed: false, + currency: '', + price: 0, + total: 0, + totalZec: 0, + paid: false, + externalInvoice: '', + shortCode: '', + lines: [ + { + qty: 1, + name: '', + cost:0 + } + ] + }; + private invData_raw : string = ''; private invData_buff : any = null; - public reportType = 0; + public reportType = 1000; public Status = 0; + zPrice: number = 1.0; + name: string = ''; + error: boolean = false; + codeString: string = 'Test'; + orderId : string = ''; + constructor(private activatedRoute : ActivatedRoute, private http : HttpClient ) {} @@ -87,7 +122,7 @@ export class PmtserviceComponent implements OnInit { this.pmtData.amount = params["amount"]; this.pmtData.currency = params["currency"]; this.pmtData.shortcode = params["shortCode"]; - console.log(this.pmtData); +// console.log(this.pmtData); this.getInvoiceData( this.pmtData ); @@ -101,7 +136,8 @@ export class PmtserviceComponent implements OnInit { // Verify owner id ( Status = 1 if not exists ) // ( Status = 2 if service not available for user ) // - console.log('getOwner -> ', reqData.ownerId); +// console.log('getOwner -> '+ reqData.ownerId); +// console.log('received amount -> ' + reqData.amount); const ownParams = new HttpParams().append('id', reqData.ownerId); let obs = this.http.get<{message:string, owner: any}> ( this.beUrl+'api/ownerid', @@ -117,11 +153,6 @@ export class PmtserviceComponent implements OnInit { // ==> remove "== false" for production enviroment // if ( this.owner.payconf == false) { - // verifiy if an order for requested invoice - // already exist, If exists, delete it and create - // a new one if it has not been paid in ZGo - // otherwise report payment - // process data console.log("Owner check passed!!!"); this.getXeroInvoiceData( reqData ); @@ -140,71 +171,159 @@ export class PmtserviceComponent implements OnInit { getXeroInvoiceData( reqData : PmtData ) { - // Call Xero API +/* + // Call test Xero API let url : string = "http://localhost:3000/xero/" + reqData.invoice; this.http .get(url) - .subscribe( data => { - console.log('Data >>> ' + data); - this.invData_raw = data.message.replaceAll("'",'"'); - this.invData_buff = JSON.parse(this.invData_raw); - console.log('Invoice : >> ' + this.invData_raw); - this.invData.inv_Type = this.invData_buff.type; - this.invData.inv_Id = this.invData_buff.invoiceID; - this.invData.inv_No = this.invData_buff.invoiceNumber; - this.invData.inv_Contact = this.invData_buff.contact.name; - this.invData.inv_Currency = this.invData_buff.currencyCode; - this.invData.inv_CurrencyRate = this.invData_buff.currencyRate; - this.invData.inv_Total = this.invData_buff.total; - this.invData.inv_Status = this.invData_buff.status; - this.invData.inv_Date = new Date(this.invData_buff.date); - this.invData.inv_shortCode = reqData.shortcode; - // invoice number found, test if it's type is correct - if ( this.invData.inv_Type == 'ACCREC' ) { - console.log('Invoice type is correct!!'); - // Test if invoice is not already paid - if ( this.invData.inv_Status == 'AUTHORISED') { - console.log('invoice is payable'); - // Test if Invoice's currency is supported - if ( this.invData.inv_Currency == reqData.currency ) { - console.log('Invoice currency supported'); - // Test if requested amount is as reported by Xero - if ( this.invData.inv_Total == reqData.amount ) { - console.log('Invoice amount Ok - create Order'); -// -// =====> Create order here -// +*/ + console.log('>> find current zcash price'); + this.getPrice(this.owner.currency); + + console.log('get Invoice -> ' + reqData.invoice); + let invParams = new HttpParams(); + invParams = invParams.append('address', this.owner.address); + invParams = invParams.append('inv', reqData.invoice); + let inv = this.http.get<{message:string, invData: any}> + ( this.beUrl+'api/invdata', + { headers: this.reqHeaders, + params: invParams, + observe: 'response'}); + inv.subscribe( invDataResponse => { +// console.log('Response from ZGo-Xero'); +// console.log(invDataResponse.status); + this.invData_buff = invDataResponse.body; + this.invData.inv_Type = this.invData_buff.invdata.inv_Type; + this.invData.inv_Id = this.invData_buff.invdata.inv_Id; + this.invData.inv_No = this.invData_buff.invdata.inv_No; + this.invData.inv_Contact = this.invData_buff.invdata.inv_Contact; + this.invData.inv_Currency = this.invData_buff.invdata.inv_Currency; + this.invData.inv_CurrencyRate = this.invData_buff.invdata.inv_CurrencyRate; + this.invData.inv_Total = this.invData_buff.invdata.inv_Total; + this.invData.inv_Status = this.invData_buff.invdata.inv_Status; + this.invData.inv_Date = this.invData_buff.invdata.inv_Date; + this.invData.inv_shortCode = reqData.shortcode; + /* + console.log('>>> inv_Type -> ' + this.invData.inv_Type); + console.log('>>> inv_Id -> ' + this.invData.inv_Id); + console.log('>>> inv_No -> ' + this.invData.inv_No); + console.log('>>> inv_Contact -> ' + this.invData.inv_Contact); + console.log('>>> inv_Currency-> ' + this.invData.inv_Currency); + console.log('>>> inv_CurrencyRate -> ' + this.invData.inv_CurrencyRate); + console.log('>>> inv_Total -> ' + this.invData.inv_Total); + console.log('>>> inv_Status-> ' + this.invData.inv_Status); + console.log('>>> inv_Date -> ' + this.invData.inv_Date); +*/ + if ( this.invData.inv_Type == 'ACCREC' ) { + console.log('Invoice type is correct!!'); + // Test if invoice is not already paid + if ( this.invData.inv_Status == 'AUTHORISED') { + console.log('invoice is payable'); + // Test if Invoice's currency is supported + if ( this.invData.inv_Currency == reqData.currency ) { + console.log('Invoice currency supported'); + // Test if requested amount is as reported by Xero + if ( this.invData.inv_Total == reqData.amount ) { + console.log('Invoice amount Ok - create Order'); + // =====> Create order here + this.createOrder(); + // + } else { + console.log('Invoice amount does not match') + this.reportType = 8; + } } else { - console.log('Invoice amount does not match') - this.reportType = 8; + console.log('Invoice currency not supported'); + this.reportType = 7; } } else { - console.log('Invoice currency not supported'); - this.reportType = 7; + console.log('Invoice already paid'); + this.reportType = 6; } } else { - console.log('Invoice already paid'); - this.reportType = 6; + console.log('Invoice type is invalid' ); + this.reportType = 5; } - } else { - console.log('Invoice type is invalid' ); - this.reportType = 5; - } - // Save invData in database - }, - error => { - if ( error.status == 404 ) { - this.reportType = 4; - console.log('Invoice not found (' + JSON.stringify(error) +')' ); - } else { - this.reportType = 3; - console.log('Xero server inaccesible! (' + JSON.stringify(error) + ')'); - } - return 2; - }, - () => { - console.log("Request complete") - }); + }, error => { + console.log("Error while getting invData!!!"); + console.log(error); + }); } -} + + createOrder() { + this.reportType = 0; +// console.log('Starting order generation'); +// console.log('>> find current zcash price'); + + this.order = { + _id: '', + address: this.owner.address, + session: 'Xero-' + this.owner._id, + currency: this.owner.currency, + timestamp: new Date(Date.now()).toISOString(), + closed: true, + totalZec: this.invData.inv_Total/this.zPrice, + price: this.zPrice, + total: this.invData.inv_Total, + paid: false, + externalInvoice: this.invData.inv_No, + shortCode: this.invData.inv_shortCode, + lines: [{qty: 1, + name: 'Invoice from ' + this.owner.name + '[' + this.invData.inv_No + ']', + cost: this.invData.inv_Total}] + }; + + let obs = this.http.post<{message: string, order: Order}> + (this.beUrl+'api/orderx', + {payload: this.order}, + { headers: this.reqHeaders } + ); + obs.subscribe((orderData) => { +// console.log('Order created'); + +// console.log(orderData.order); + this.order = orderData.order + console.log('>> order -> ' + JSON.stringify(this.order)); + this.orderId = String(this.order._id); + +// console.log('Generating QRCode....') + + this.codeString = `zcash:${this.order.address}?amount=${this.order.totalZec.toFixed(8)}&memo=${URLSafeBase64.encode(Buffer.from('ZGo Order::'.concat(this.orderId)))}`; + + var qrcode = new QRCode(document.getElementById("payment-qr"), { + text: this.codeString, + logo: "/assets/zcash.png", + width: 180, + height: 180, + logoWidth: 50, + logoHeight: 50, + correctLevel: QRCode.CorrectLevel.H + }); + + }); + } + + getIconStyle(order : Order) { + if( order.paid ) + return "font-size: 14px; color: #72cc50; margin-bottom: -2px;"; + return "color: #FB4F14; margin-bottom: -2px; cursor: pointer;"; + + } + + getPrice(currency: string){ + //var currency = 'usd'; + const params = new HttpParams().append('currency', currency); + let obs = this.http.get<{message: string, price: any}>(this.beUrl+'api/price', { headers:this.reqHeaders, params: params, observe: 'response'}); + obs.subscribe((PriceData) => { + if (PriceData.status == 200) { + this.zPrice = PriceData.body!.price.price; + console.log("price", this.zPrice); + } else { + console.log('No price found for currency', currency); + this.zPrice = 1.0; + } + }); + return obs; + } +} \ No newline at end of file diff --git a/src/app/pmtservice/url.txt b/src/app/pmtservice/url.txt index 7e07097..595f557 100644 --- a/src/app/pmtservice/url.txt +++ b/src/app/pmtservice/url.txt @@ -1 +1,3 @@ -http://localhost:4200/pmtservice?ownerid=62cca13f5530331e2a97c78e&invoiceNo=INV-0034¤cy=USD&amount=753.95&shortCode=!w8T62 \ No newline at end of file +http://localhost:4200/pmtservice?ownerid=62cca13f5530331e2a97c78e&invoiceNo=INV-0034¤cy=USD&amount=753.95&shortCode=!w8T62 + +https://test.zgo.cash/api/invdata?address=zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvf3sl8&inv=INV-0034 \ No newline at end of file diff --git a/src/app/pmtservice/xeroinvoice.model.ts b/src/app/pmtservice/xeroinvoice.model.ts index 5f0ed81..e906e34 100644 --- a/src/app/pmtservice/xeroinvoice.model.ts +++ b/src/app/pmtservice/xeroinvoice.model.ts @@ -1,13 +1,13 @@ export interface XeroInvoice { - inv_Type : String; - inv_Id : String; - inv_No : String; - inv_Contact : String; - inv_Currency : String; + inv_Type : string; + inv_Id : string; + inv_No : string; + inv_Contact : string; + inv_Currency : string; inv_CurrencyRate : number; inv_Total : number; - inv_Status : String; + inv_Status : string; inv_Date : Date; - inv_shortCode : String; + inv_shortCode : string; inv_ProcDate : Date; } \ No newline at end of file