diff --git a/AccountingIntegration.odt b/AccountingIntegration.odt new file mode 100644 index 0000000..8dbef39 Binary files /dev/null and b/AccountingIntegration.odt differ diff --git a/AccountingIntegration.pdf b/AccountingIntegration.pdf new file mode 100644 index 0000000..e0f2ba2 Binary files /dev/null and b/AccountingIntegration.pdf differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 99642c0..fd819b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ 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 diff --git a/CurrencyCodes.ods b/CurrencyCodes.ods new file mode 100644 index 0000000..f01dba3 Binary files /dev/null and b/CurrencyCodes.ods differ diff --git a/src/app/pmtservice/pmtservice.component.css b/src/app/pmtservice/pmtservice.component.css index e69de29..f018ed3 100644 --- a/src/app/pmtservice/pmtservice.component.css +++ b/src/app/pmtservice/pmtservice.component.css @@ -0,0 +1,24 @@ +.invoice { + font-family: Roboto Mono !important; +} + +.zecSign { + margin-bottom: -4px; + font-size: 18px; + height: 18px; +} + +.invoiceHeader { + display: flex; + font-family: Spartan; + font-weight: 700; + font-size: 26px; + color: white; + justify-content: space-between; + line-height: 40px; + padding: 10px; + vertical-align: center; + max-width: 600px; + background: #ff5722; +} + diff --git a/src/app/pmtservice/pmtservice.component.html b/src/app/pmtservice/pmtservice.component.html index d7bbf3a..9b2cb25 100644 --- a/src/app/pmtservice/pmtservice.component.html +++ b/src/app/pmtservice/pmtservice.component.html @@ -1 +1,163 @@ -

{{ pmtData.ownerId }}

+
+
+
+ +
+
+
+
+
+ Invalid Owner ID!! +
+
+
+ Payment request was not processed!! +
+
+
+
+
+
+
+ Payment service not
+ enabled for
+ {{ owner.name}} +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Connection to Xero
server failed!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Invoice
{{ pmtData.invoice }}
not found!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Invoice
{{ pmtData.invoice }}
type invalid!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Invoice
{{ pmtData.invoice }}
already paid!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Currency
[ {{ pmtData.currency }} ]
not supported!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Amount does not
+ match value
+ reported by Xero!! +
+
+
+ Payment request was not processed!! +
+
+
+ +
+
+
+
+ Invoice Goes here!!! +
+
+
+ Payment request was not processed!! +
+
+
+ + + +
+
\ No newline at end of file diff --git a/src/app/pmtservice/pmtservice.component.ts b/src/app/pmtservice/pmtservice.component.ts index 543dc24..9b16631 100644 --- a/src/app/pmtservice/pmtservice.component.ts +++ b/src/app/pmtservice/pmtservice.component.ts @@ -1,6 +1,14 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, Params } from "@angular/router"; -import { PmtData } from "./pmtservice.model" +import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http"; +import { PmtData } from "./pmtservice.model"; +import { XeroInvoice } from "./xeroinvoice.model"; +import { Owner } from '../owner.model'; +import { ConfigData } from '../configdata'; +import { Item } from '../items/item.model' + +var Buffer = require('buffer/').Buffer; + @Component({ selector: 'app-pmtservice', @@ -10,6 +18,8 @@ import { PmtData } from "./pmtservice.model" export class PmtserviceComponent implements OnInit { + beUrl = ConfigData.Be_URL; + private reqHeaders: HttpHeaders = new HttpHeaders(); public pmtData : PmtData = { ownerId :'', @@ -19,18 +29,174 @@ export class PmtserviceComponent implements OnInit { shortcode: '' }; - constructor(private activatedRoute: ActivatedRoute) {} + public invData : XeroInvoice = { + inv_Type : '', + inv_Id : '', + inv_No : '', + inv_Contact : '', + inv_Currency : '', + inv_CurrencyRate : 0, + inv_Status : '', + inv_Total : 0, + inv_Date : new Date(), + inv_shortCode : '', + inv_ProcDate : new Date() + }; + + public owner: Owner = { + address: '', + name: '', + currency: 'usd', + tax: false, + taxValue: 0, + vat: false, + vatValue: 0, + first: '', + last: '', + email: '', + street: '', + city: '', + state: '', + postal: '', + phone: '', + paid: false, + website: '', + country: '', + zats: false, + invoices: false, + expiration: new Date(Date.now()).toISOString(), + payconf: false, + viewkey: '' + }; + private invData_raw : string = ''; + private invData_buff : any = null; + + public reportType = 0; + public Status = 0; + + constructor(private activatedRoute : ActivatedRoute, + private http : HttpClient ) {} ngOnInit() { - this.activatedRoute.queryParams.subscribe((params) => { + var auth = 'Basic ' + Buffer.from(ConfigData.UsrPwd).toString('base64'); + this.reqHeaders = new HttpHeaders().set('Authorization', auth); + this.activatedRoute.queryParams.subscribe((params) => { this.pmtData.ownerId = params["ownerid"]; - this.pmtData.invoice = params["invoice"]; + this.pmtData.invoice = params["invoiceNo"]; this.pmtData.amount = params["amount"]; this.pmtData.currency = params["currency"]; - this.pmtData.shortcode = params["shortcode"]; - + this.pmtData.shortcode = params["shortCode"]; console.log(this.pmtData); + + this.getInvoiceData( this.pmtData ); + }); + + } + + getInvoiceData( reqData : PmtData ) { + + // + // Verify owner id ( Status = 1 if not exists ) + // ( Status = 2 if service not available for user ) + // + console.log('getOwner -> ', reqData.ownerId); + const ownParams = new HttpParams().append('id', reqData.ownerId); + let obs = this.http.get<{message:string, owner: any}> + ( this.beUrl+'api/ownerid', + { headers: this.reqHeaders, + params: ownParams, + observe: 'response'}); + obs.subscribe((OwnerDataResponse) => { + //console.log('api/getowner', OwnerDataResponse.status); + if (OwnerDataResponse.status == 200) { + this.owner = OwnerDataResponse.body!.owner; + console.log('Owner => ' + this.owner.name ); + if ( this.owner.payconf == false ) { + // process data + console.log("Owner check passed!!!"); + this.getXeroInvoiceData( reqData ); + } else { + console.log("Owner check failed!!!") + this.reportType = 2; + }; + } else { + if ( OwnerDataResponse.status == 204 ) { + console.log('Res.Status = ' + OwnerDataResponse.status) + console.log('Owner id not found!!!'); + this.reportType = 1; + } + }}); + + } + + getXeroInvoiceData( reqData : PmtData ) { + + // Call 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 +// + } else { + console.log('Invoice amount does not match') + this.reportType = 8; + } + } else { + console.log('Invoice currency not supported'); + this.reportType = 7; + } + } else { + console.log('Invoice already paid'); + this.reportType = 6; + } + } 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") + }); } } diff --git a/src/app/pmtservice/url.txt b/src/app/pmtservice/url.txt index 1d562d8..7e07097 100644 --- a/src/app/pmtservice/url.txt +++ b/src/app/pmtservice/url.txt @@ -1 +1 @@ -http://localhost:4200/pmtservice?ownerid=Rene&amount=30¤cy=USD&invoice=INV-003234&shortcode=abcde \ No newline at end of file +http://localhost:4200/pmtservice?ownerid=62cca13f5530331e2a97c78e&invoiceNo=INV-0034¤cy=USD&amount=753.95&shortCode=!w8T62 \ No newline at end of file diff --git a/src/app/pmtservice/xeroinvoice.model.ts b/src/app/pmtservice/xeroinvoice.model.ts new file mode 100644 index 0000000..5f0ed81 --- /dev/null +++ b/src/app/pmtservice/xeroinvoice.model.ts @@ -0,0 +1,13 @@ +export interface XeroInvoice { + 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_Date : Date; + inv_shortCode : String; + inv_ProcDate : Date; +} \ No newline at end of file diff --git a/src/app/viewer/viewer.component.ts b/src/app/viewer/viewer.component.ts index ba3e9af..1133205 100644 --- a/src/app/viewer/viewer.component.ts +++ b/src/app/viewer/viewer.component.ts @@ -72,6 +72,9 @@ export class ViewerComponent implements OnInit { this.ownerUpdate.subscribe((owner) => { this.owner = owner; }); + +// console.log(this.owner._id); + this.userUpdate = userService.userUpdate; this.userUpdate.subscribe((user) => { this.user = user;