소스 검색

recent employee, recent clients, create invoice, first test pass

removed xeroauth1 files

missing sync_wp  add clients and add employees
master
sp 4 년 전
부모
커밋
69bed6f2fe
7개의 변경된 파일41개의 추가작업 그리고 789개의 파일을 삭제
  1. +0
    -239
      TimeSheet.php
  2. +0
    -495
      XeroOauth1.php
  3. +4
    -22
      XeroOauth2.php
  4. +2
    -4
      XeroOauth2ShortCode.php
  5. +2
    -2
      XeroOauth2Timesheet.php
  6. +2
    -2
      html/bts_client_invoice_template.html
  7. +31
    -25
      ts.php

+ 0
- 239
TimeSheet.php 파일 보기

@@ -1,239 +0,0 @@
<?php

namespace Biukop;

class TimeSheet{
private $xero ;
private $start_date;
private $end_date;
private $remote_timesheets;
private $local_timesheets =[];
private $buddy_timesheets =[];
private $warning_timesheets =[];
public function __construct($xero, $end_date){
$this->xero = $xero;
$this->end_date = $end_date;
$this->cal_start(); //set start_date;
$this->get_remote_timesheets();
}
private function cal_start(){
$d = new \DateTime($this->end_date);
$d->modify("-13 days");
$this->start_date = $d->format("Y-m-d");
// wp_send_json(array(
// 'start'=> $this->start_date,
// 'finish'=> $this->end_date,
// ));
}
public function refresh_remote(){
$this->get_remote_timesheets();
}
private function get_remote_timesheets()
{
$this->remote_timesheets = $this->xero->load('PayrollAU\\Timesheet')
->where('EndDate==DateTime.Parse("'. $this->end_date .'")')
->execute();
}
public function get_xero_timesheet()
{
return $this->remote_timesheets;
}
public function get_local_timesheet()
{
return $this->local_timesheets;
}
public function set_local_timesheet($lines)
{
$this->local_timesheets = [];
//convert $val to Timesheet format;
foreach ($lines as $staff_login => $rateshours){
$ts = "";
if (array_key_exists($staff_login, $this->local_timesheets)){
$ts = $this->local_timesheets[$staff_login];
}else{
$ts = new \XeroPHP\Models\PayrollAU\Timesheet($this->xero);
$ts->setEmployeeID($staff_login)
->setTimeSheetID($this->get_timesheet_id_by_employee_id($staff_login))
->setStartDate(new \DateTime($this->start_date))
->setEndDate(new \DateTime($this->end_date))
->setStatus("DRAFT");
}
//adding lines
foreach ($rateshours as $rateid => $hours)
{
$ts_line = new \XeroPHP\Models\PayrollAU\Timesheet\TimesheetLine($this->xero);
$ts_line->setEarningsRateID($rateid);
for ($i=0; $i<14; $i++){
$ts_line->addNumberOfUnit($hours[$i]);
}
$ts->addTimesheetLine($ts_line);
}
//update this timesheet;
$this->local_timesheets[$staff_login] = $ts;
}
}
public function save_to_xero()
{
$to_save=[];
foreach ( $this->local_timesheets as $t){
$buddy = $this->get_buddy_timesheet_by_ts($t);
if ($buddy != NULL && $buddy->getStatus() != "DRAFT"){
continue;//we encountered approved timesheet;
}
$t->setDirty('EmployeeID');
$t->setDirty('StartDate');
$t->setDirty('EndDate');
$t->setDirty('TimesheetLines');
$t->setDirty('Status');
$t->setDirty('Hours');
$t->setDirty('TimesheetID');
$t->setStatus('DRAFT');
$to_save[]=$t;
}
//empty remote timesheet which are not available in local
//
//some of buddy timesheets might be removed from local already
//we cannot delete it but we can set it to 0 hours
//
foreach ($this->remote_timesheets as $ts)
{
$staff_login = $ts->getEmployeeID();
if (!array_key_exists($staff_login, $this->local_timesheets)){//not found
//we create empty timesheets for him/her
$empty = new \XeroPHP\Models\PayrollAU\Timesheet($this->xero);
$empty->setEmployeeID($staff_login)
->setTimeSheetID($ts->getTimesheetID())
->setStartDate(new \DateTime($this->start_date))
->setEndDate(new \DateTime($this->end_date))
->setStatus("DRAFT");
foreach($ts->getTimesheetLines() as $line){
$eid = $line->getEarningsRateID();
$zeroline= $this->create_empty_timesheet_lines($eid);
$empty->addTimesheetLine($zeroline);
}
if ( $ts->getStatus() == "DRAFT" ){//good, we can save it;
$to_save[] = $empty;//add it to save
}else{
$staff_name = \Biukop\AcareOffice::get_user_name_by_login($staff_login);
$msg = sprintf("%s : %s is APPROVED, but needs to be empty it",
$staff_name,
$ts->getTimeSheetID());
\Biukop\AcareOffice::log($msg);
}
}
}
$this->xero->saveAll($to_save, false);
}
private function create_empty_timesheet_lines($EarningsRateID)
{
$line = new \XeroPHP\Models\PayrollAU\Timesheet\TimesheetLine($xero);
$line->setEarningsRateID($EarningsRateID);
for ($i=0; $i<14; $i++)
$line->addNumberOfUnit(0);
return $line;
}
private function get_timesheet_id_by_employee_id($id)
{
foreach ($this->remote_timesheets as $ts)
{
$staff_login = $ts->getEmployeeID();
if($staff_login == $id){
return $ts->getTimesheetID();
}
}
return NULL;
}
public function warning_timesheet()
{
return $this->warning_timesheets;
}
public function approve_all(){
$to_save=[];
foreach ( $this->remote_timesheets as $t){
if($t->getStatus() == 'DRAFT'){
$t->setDirty('EmployeeID');
$t->setDirty('StartDate');
$t->setDirty('EndDate');
$t->setDirty('TimesheetLines');
$t->setDirty('Status');
$t->setDirty('Hours');
$t->setDirty('TimesheetID');
$t->setStatus('APPROVED');
$to_save[]=$t;
}
}
$this->xero->saveAll($to_save, false);
}
public function get_buddy_timesheets($employee_id, $start, $end)
{
foreach ($this->remote_timesheets as $t){
if ( $t->getEmployeeID() == $employee_id &&
$t->getStartDate()->format('Y-m-d') == $start->format('Y-m-d') &&
$t->getEndDate()->format('Y-m-d') == $end->format('Y-m-d') )
{
return $t;
}
}
return NULL; //not found;
}
private function get_buddy_timesheet_by_ts($t)
{
$employee_id = $t->getEmployeeID();
$start = $t->getStartDate();
$end = $t->getEndDate();
return $this->get_buddy_timesheets($employee_id, $start, $end);
}
public function main(){
$this->warning_timesheets = [];
$this->buddy_timesheets = [];
$this->local_timesheets = $this->create_timesheet_from_db(
new DateTime("2019-07-01"),
new DateTime("2019-07-14")
);
$length = count($this->local_timesheets);
$to_save =[];
for ($i =0; $i < $length; $i++)
{
$me = $this->local_timesheets[$i];
$buddy = $this->get_buddy_timesheet_by_ts($me);
$this->buddy_timesheets[$i] = $buddy;
if ( $buddy != NULL ) {
$timesheet_id = $buddy->getTimeSheetID();
$me->setTimeSheetID($timesheet_id);
if ( $buddy->getStatus() != 'DRAFT'){
$this->warning_timesheets[]=$me;
continue;
}else{
$to_save[]=$me;
}
}else{
$to_save[]=$me;
}
}
$this->xero->saveAlL($to_save, false); //false do not check GUID, always use POST; not PUT
//$this->approve_all();
}

}

+ 0
- 495
XeroOauth1.php 파일 보기

@@ -1,495 +0,0 @@
<?php
namespace Biukop;

use \XeroPHP\Application\PrivateApplication;
use \XeroPHP\Remote\Exception\RateLimitExceededException;
use \XeroPHP\Remote\Exception\NotFoundException;

class XeroOauth1 {
private $xero;
private $clientgroup="48646f3d-cf5e-4fea-8c8b-5812bd540e1b";
private $minimum_sync_interval_in_seconds = 600;
private function default_config(){
$config = array(
'oauth' => [
'callback' => 'http://acaresydney.com.au/',
'consumer_key' => 'G6AJIRWTH0X3C5SVS3ETZXNFCMDNGG',
'consumer_secret' => 'LP0PTSBCJLBB4CGYYKOHDXYF2NWXWD',
'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem',
],
);
return $config;
}
private function office_config(){
$office_config = [
'xero' => [
// 'payroll_version' =>'1.9',
],
'curl' => [
CURLOPT_USERAGENT =>'AcareSydneyWebOffice',
],
'oauth' => [
'callback' => 'http://acaresydney.com.au/',
'consumer_key' => 'JE4LWKCJ6NHED30RFZWCT7WQYTS8JD',
'consumer_secret' => 'JXVZAZWKGM7MLUZSVIMK7ZSJE9GNYQ',
'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem',
],
];
return $office_config;
}
public function __construct(){
$this->xero = new PrivateApplication($this->office_config());
}
public function get_xero_handle()
{
return $this->xero;
}
public function getClients($contact_group_id){
$xero = $this->xero;
$cg = $xero->loadByGUID("Accounting\\ContactGroup", $contact_group_id);
$contacts = $cg->getContacts();
return $contacts;
}
public function getContact($id){
$user = $this->xero->loadByGUID("Accounting\\Contact",$id);
return $user;
}
public function getEmployees(){
$employees = $this->xero->load("PayrollAU\\Employee")
->where('EmployeeGroupName="Web-Employee"')
->execute();
return $employees;
}
public function getEmployee($id){
$employee = $this->xero->loadByGUID("PayrollAU\\Employee",$id);
return $employee;
}
//
//sync users to wordpress system
//does not work for too many users or employees
public function sync_users($mininterval, $employeeonly, $clientsonly){
$this->usage();
$this->minimum_sync_interval_in_seconds = $mininterval;
$msg="Sync users with minimum interval set to $mininterval \n";
$this->logConsole($msg);
try{
if ($clientsonly){
$this->sync_clients();
}else if ($employeeonly){
$this->sync_employees();
}else{
$this->sync_clients();
$this->sync_employees();
}
}catch(RateLimitExceededException $e){
$msg= "XeroOauth1 API rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n";
$this->logConsole($msg);
}catch(NotFoundException $e){
$msg= "XeroOauth1 API resource not found rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n";
$this->logConsole($msg);
}
}
private function sync_clients($add_new_only = false){
$contacts = $this->getClients($this->clientgroup);
//add new first;
$to_update = [];
foreach ($contacts as $c){
$login = $c->getContactID();
$user = get_user_by('login', $login);
if ($user === false){
$this->add_new_contact($c);
}else{
$to_update[] = $c; // to update users later;
}
}
if ($add_new_only)
return;
//sync existing
foreach ($to_update as $c){
$msg = sprintf("SYNC Client name=[%s] {%s} \n", $c->getName(), $c->getContactID());
$this->logConsole($msg);
$this->update_existing_contact($c);
}
}
private function sync_employees($add_new_only = false){
$employees = $this->getEmployees();
//add new staff
foreach ( $employees as $e){
$login = $e->getEmployeeID();
$user = get_user_by('login', $login);
if ($user === false){
$this->add_new_staff($e);
}else{
$to_update[] = $e; // to update exiting users later;
}
}
if ($add_new_only)
return;
foreach ( $to_update as $e){
$msg = sprintf("SYNC employee name=[%s %s] {%s} \n", $e->getFirstName(), $e->getLastName(), $e->getEmployeeID());
$this->logConsole($msg);
$this->update_existing_staff($e);
}
}
private function add_new_contact($contact){
$login = $contact->getContactID();
$user = get_user_by('login', $login);
if ($user === false){
$msg = sprintf("ADD Client name=[%s] {%s} \n", $contact->getName(), $contact->getContactID());
$this->logConsole($msg);
$xero_contact = $this->getContact($login);
$args = $this->xero_contact_profile($xero_contact);
$id = wp_insert_user($args);
if (! $id instanceof \WP_Error){
$user = get_user_by('ID', $id);
update_user_meta($user->ID, 'address', $args['address']);
update_user_meta($user->ID, 'account', $args['account']);
}else{
$msg = "==(Add Client failed)==";
$this->logConsole($msg);
$msg = sprintf("ADD Client name=[%s] {%s} Failed\n", $contact->getName(), $contact->getContactID());
error_log("ACARE add client failed: $msg");
}
}
}
private function update_existing_contact($contact){
$login = $contact->getContactID();
$user = get_user_by('login', $login);
if ($user !== false)
{//update user - must be existing user;
if ($this->is_too_close_to_sync($user)){
return;
}
$xero_contact = $this->getContact($login);
$args = $this->xero_contact_profile($xero_contact);
$args['ID'] = $user->ID;
unset($args['user_pass']); //we don't change password
wp_update_user($args);
update_user_meta($user->ID, 'address', $args['address']);
update_user_meta($user->ID, 'account', $args['account']);
}
$this->mark_updated($user->ID);
}
private function xero_contact_profile($c){
$args = [
'user_login' => $username = $c->getContactID(),
'user_pass' => md5(uniqid(rand() + time(), true)),
'display_name' =>$c->getName(),
'user_email' => $c->getEmailAddress(),
'first_name' => $c->getFirstName(),
'last_name' => $c->getLastName(),
'nickname' => $c->getName(),
'account' => $c->getAccountNumber(),
'address'=> $this->get_post_address($c),
'role' => 'client',
];
return $args;
}
private function get_post_address($client){
$result = "";
$addr = $this->get_client_address_by_type($client, 'POBOX');
if ( $addr != false){
if ($addr->getAddressLine1() != ""){
$result .= $addr->getAddressLine1() . ";";
}
if ($addr->getAddressLine2() != ""){
$result .= $addr->getAddressLine2() . ";";
}
if ($addr->getAddressLine3() != ""){
$result .= $addr->getAddressLine3() . ";";
}
if ($addr->getAddressLine4() != ""){
$result .= $addr->getAddressLine4() . ";";
}
if ($addr->getCity() != ""){
$result .= $addr->getCity() . ";";
}
if ($addr->getPostalCode() != ""){
$result .= $addr->getPostalCode() . ";";
}
}
echo "result for client is " . $result . "\n";
return $result;
}
private function get_client_address_by_type($client, $t){
$addr = false;
foreach( $client->getAddresses() as $a){
if( $a->getAddressType() == $t){
$addr = $a;
break;
}
}
return $addr;
}
private function add_new_staff($employee)
{
$login = $employee->getEmployeeID();
$user = get_user_by('login', $login);
if ($user === false){
$msg = sprintf("ADD employee name=[%s %s] {%s} \n",
$employee->getFirstName(),
$employee->getLastName(),
$employee->getEmployeeID());
$this->logConsole($msg);
$xero_employee = $this->getEmployee($login);
$args = $this->xero_employee_profile($xero_employee);
$id = wp_insert_user($args);
if (! $id instanceof \WP_Error){
$user = get_user_by('ID', $id);
update_user_meta($user->ID, 'mobile', $args['mobile']);
update_user_meta($user->ID, 'address', $args['address']);
}else{
$msg = "==(Add staff failed)==";
$this->logConsole($msg);
$msg = sprintf("ADD employee name=[%s %s] {%s} Failed\n",
$employee->getFirstName(),
$employee->getLastName(),
$employee->getEmployeeID());
error_log("ACARE add employee failed: $msg");
}
}
}
private function update_existing_staff($employee)
{
$login = $employee->getEmployeeID();
$user = get_user_by('login', $login);
if ($this->is_too_close_to_sync($user)){
return;
}
if ($user != false) {
$xero_employee = $this->getEmployee($login);
$args = $this->xero_employee_profile($xero_employee);
$args['ID'] = $user->ID;
unset($args['user_pass']);
wp_update_user($args);
update_user_meta($user->ID, 'mobile', $args['mobile']);
update_user_meta($user->ID, 'address', $args['address']);
}
$this->mark_updated($user->ID);
}
private function xero_employee_profile($e){
$args = [
'user_login' => $username = $e->getEmployeeID(),
'user_pass' => md5(uniqid(rand() + time(), true)),
'display_name' =>$e->getFirstName() . " " . $e->getLastName(),
'user_email' => $e->getEmail(),
'first_name' => $e->getFirstName(),
'last_name' => $e->getLastName(),
'nickname' => $e->getFirstName(),
'mobile' => $e->getMobile(),
'address'=> $this->get_employee_address($e),
'role' => 'staff',
];
return $args;
}
private function get_employee_address($e){
// "HomeAddress": {
// "AddressLine1": "16 Quist Avenue",
// "City": "Lurnea",
// "Region": "NSW",
// "PostalCode": "2170",
// "Country": "AUSTRALIA"
// },
$addr = "";
$home = $e->getHomeAddress();
$addr .= $home->getAddressLine1() .",";
$addr .= $home->getAddressLine2() .",";
$addr .= $home->getCity() . ",";
$addr .= $home->getRegion() . " ";
$addr .= $home->getCountry() ." ";
$addr .= $home->getPostalCode();
return $addr;
}
private function mark_updated($userid){
update_user_meta($userid, 'lastsync', time());
}
private function get_last_sync($userid){
$lastsync = get_user_meta($userid, 'lastsync', true);
return (int)($lastsync);
}
private function is_too_close_to_sync($user){
$userid = $user->ID;
$lastsync = $this->get_last_sync($user->ID);
$now = time();
$diff = $now - (int) $lastsync;
if ($diff < $this->minimum_sync_interval_in_seconds){
$msg = sprintf("\tSKIP userid(%d),login=%s,display_name=%s,(lastsync=%d secs ago, mininterval=%d) \n",
$user->ID, $user->user_login, $user->display_name, $diff, $this->minimum_sync_interval_in_seconds);
$this->logConsole($msg);
return true;
}
return false;
}
private function logConsole($str){
//if is commandline
if ( defined( 'WP_CLI' ) && WP_CLI ) {
echo $str;
}
}
private function usage(){
$msg = "_____________________________________________\n";
$msg .= "run this command at public_html/, where wp-config.php exist \n";
$msg .= "wp sync_users --mininterval=6000 \n";
$msg .= "6000 means those users synced within 6000 seconds will be bypassed \n";
$msg .= "to sync everything \n";
$msg .= "wp sync_users --mininterval=0 [--clientsonly] [--employeeonly]\n";
$msg .= "but it may hit XERO rate limit, 60call/sec, 5000/day \n";
$msg .= "---------------------------------------------\n";
$this->logConsole($msg);
}
/* sync payitems to wp options */
public function init_wp(){
try{
$this->sync_payitem();
$this->add_new_client();
$this->add_new_employee();
$this->sync_payroll_calendar();
}catch(\XeroPHP\Remote\Exception $e){
}
}

private function add_new_client(){
if ($this->too_close_to_add_client()){
return;
}
update_option('bts_add_client_last_sync', time());
$this->sync_clients(true);//add new only;
}
private function add_new_employee(){
if ($this->too_close_to_add_employee()){
return;
}
update_option('bts_add_employee_last_sync', time());
$this->sync_employees(true);//add new only;
}
private function sync_payroll_calendar()
{
if ($this->too_close_to_sync_payroll_calendar()){
return;
}
update_option('bts_pay_roll_calendar_last_sync', time());
$pc = $this->get_payroll_calendar();
$start = $pc->getStartDate()->format('Y-m-d');
$finish = new \DateTime($start);
$finish = $finish->modify("+13 days")->format('Y-m-d');
$paydate = $pc->getPaymentDate()->format('Y-m-d');
$calendar["start"] = $start;
$calendar["finish"] = $finish;
$calendar["paydate"] = $paydate;

update_option('bts_pay_roll_calendar', $calendar);
}
private function sync_payitem(){
if ($this->too_close_to_sync_payitem()){
return;
}
$payitems = $this->xero->load('PayrollAU\\PayItem')->execute();
$payitem_options = array();
foreach ($payitems[0]->getEarningsRates() as $e){
// "EarningsRateID": "34e17d08-237a-4ae2-8115-375d1ff8a9ed",
// "Name": "Overtime Hours (exempt from super)",
// "EarningsType": "OVERTIMEEARNINGS",
// "RateType": "MULTIPLE",
// "AccountCode": "477",
// "Multiplier": 1.5,
// "IsExemptFromTax": true,
// "IsExemptFromSuper": true,
// "AccrueLeave": false,
// "IsReportableAsW1": true,
// "UpdatedDateUTC": "2019-03-16T13:18:19+00:00",
// "CurrentRecord": false
if ($e->getCurrentRecord() == "true"){
$payitem_options[]= array(
'EarningsRateID' => $e->getEarningsRateID(),
'Name'=> $e->getName(),
'EarningsType'=> $e->getEarningstype(),
'RatePerUnit' => $e->getRatePerUnit(),
'RateType' => $e->getRateType(),
'AccountCode' => $e->getAccountCode(),
"Multiplier"=> $e->getMultiplier(),
"IsExemptFromTax" => $e->getIsExemptFromTax(),
"IsExemptFromSuper"=> $e->getIsExemptFromSuper(),
"AccrueLeave" => $e->getAccrueLeave(),
"TypeOfUnits" => $e->getTypeOfUnits(),
"CurrentRecord"=> $e->getCurrentRecord(),
);
}
}
update_option('bts_payitem_earnings_rate', $payitem_options);
update_option('bts_payitem_last_sync', time());
}
private function too_close_to_sync_payitem(){
$lastsync = get_option('bts_payitem_last_sync', 0);
$now = time();
$diff = $now - (int) $lastsync;
return $diff < $this->minimum_sync_interval_in_seconds; //default 10 minutes
}
private function too_close_to_add_employee(){
$lastsync = get_option('bts_add_employee_last_sync', 0);
$now = time();
$diff = $now - (int) $lastsync;
return $diff < 1.5 * $this->minimum_sync_interval_in_seconds; //default 1.1 * 10 minutes
}
private function too_close_to_add_client(){
$lastsync = get_option('bts_add_client_last_sync', 0);
$now = time();
$diff = $now - (int) $lastsync;
return $diff < 2.0 * $this->minimum_sync_interval_in_seconds; //default 1.2 * 10 minutes
}
private function too_close_to_sync_payroll_calendar(){
$lastsync = get_option('bts_pay_roll_calendar_last_sync', 0);
$now = time();
$diff = $now - (int) $lastsync;
return $diff < 3.0 * $this->minimum_sync_interval_in_seconds; //default 1.3 * 10 minutes
}
public function get_payroll_calendar()
{
$id = "33dc7df5-3060-4d76-b4da-57c20685d77d"; //fortnightly
$pc = $this->xero->loadByGUID('PayrollAU\\PayrollCalendar', $id);
return $pc;
}
}

+ 4
- 22
XeroOauth2.php 파일 보기

@@ -17,41 +17,23 @@ use phpDocumentor\Reflection\DocBlock\Tags\Method;
class XeroOAuth2
{
private $office; // parent

private $clientID = '83CC79EEC6A54B4E8C2CA7AD61D1BF69';
private $clientSecret = 'axgKF-Ri60D89conDFhqZsi1wu7uLdQFGvMpino9nI-nfO3f';
private $clientContactGroupID="48646f3d-cf5e-4fea-8c8b-5812bd540e1b";

private $shortcodes;

public $provider;
public $options = [
'scope' => ['openid email profile offline_access assets projects accounting.settings accounting.transactions accounting.contacts accounting.journals.read accounting.reports.read accounting.attachments payroll.employees payroll.payruns payroll.payslip payroll.timesheets payroll.settings files'],
'scope1' => [
'openid',
'email',
'profile',
'offline_access',
'assets',
'projects',
'accounting.settings',
'accounting.transactions',
'accounting.contacts',
'accounting.journals.read',
'accounting.reports.read',
'accounting.attachments',
'payroll.employees',
'payroll.payruns',
'payroll.payslip',
'payroll.timesheets',
'payroll.settings'
]
'scope' => ['openid email profile offline_access assets projects accounting.settings accounting.transactions accounting.contacts accounting.journals.read accounting.reports.read accounting.attachments payroll.employees payroll.payruns payroll.payslip payroll.timesheets payroll.settings files']
];

public $storage;
public $config;
public $apiAccountingInstance; //accounting instance
public $apiPayrollInstance; // payroll au instance
public $xeroTenantId;

private $shortcodes;

public function __construct($office)
{

+ 2
- 4
XeroOauth2ShortCode.php 파일 보기

@@ -22,7 +22,7 @@ class XeroOauth2ShortCode
{
ini_set('display_errors', 'On');
$apiInstance = $this->oauth2->get_accounting_instance();
$apiResponse = $apiInstance->getOrganisations($this->xeroTenantId);
$apiResponse = $apiInstance->getOrganisations($this->oauth2->getTenantId());
return 'Organisation Name: <b> ' . $apiResponse->getOrganisations()[0]->getName() . "</b> ";
}

@@ -31,7 +31,7 @@ class XeroOauth2ShortCode
ini_set('display_errors', 'On');
$apiInstance = $this->oauth2->get_accounting_instance();

$apiResponse = $apiInstance->getContacts($this->xeroTenantId);
$apiResponse = $apiInstance->getContacts($this->oauth2->getTenantId());
$contacts = $apiResponse->getContacts();
$message = "<table> ";
$message .= "<tr> <td> # </td>
@@ -185,7 +185,6 @@ class XeroOauth2ShortCode
<td> Phone </td>
<td> Mobile </td>
<td> Start </td>
<td> Group </td>
</tr> ";
$count = 1;
foreach ($employees as $r){
@@ -200,7 +199,6 @@ class XeroOauth2ShortCode
"<td> " . $r->getPhone() . "</td> " .
"<td> " . $r->getMobile() . "</td> " .
"<td> " . $r->getStartDateAsDate()->format("M d Y") . "</td> " .
"<td> " . $r->getEmployeeGroupName() . "</td> " .
"</tr>";
$count ++;
}

+ 2
- 2
XeroOauth2Timesheet.php 파일 보기

@@ -171,8 +171,8 @@ class XeroOauth2Timesheet
{
foreach ($this->remote_timesheets as $t){
if ( $t->getEmployeeID() == $employee_id &&
$t->getStartDateAsDate()->format('Y-m-d') == $start->format('Y-m-d') &&
$t->getEndDateAsDate()->format('Y-m-d') == $end->format('Y-m-d') )
$t->getStartDateAsDate()->format('Y-m-d') == $start &&
$t->getEndDateAsDate()->format('Y-m-d') == $end )
{
return $t;
}

+ 2
- 2
html/bts_client_invoice_template.html 파일 보기

@@ -44,8 +44,8 @@
<td>{{staff_name}}</td>
<td>{{price}}</td>
<td class='invoice_nubmer'>
<img class="waiting_invoice_number" src="http://acaresydney.com.au/wp-content/plugins/ts/img/arrow.gif">
<img class="waiting_invoice_number" src="http://acaresydney.com.au/wp-content/plugins/ts/img/xero.png">
<img class="waiting_invoice_number" src="https://acaresydney.com.au/wp-content/plugins/ts/img/arrow.gif">
<img class="waiting_invoice_number" src="https://acaresydney.com.au/wp-content/plugins/ts/img/xero.png">
</td>
</tr>
{{/jobs}}

+ 31
- 25
ts.php 파일 보기

@@ -9,10 +9,9 @@
*/

namespace Biukop;
use XeroPHP\Models\Accounting\Address;
use XeroPHP\Models\Accounting\Payment;

require_once(dirname(__FILE__) . '/autoload.php');
//require_once(dirname(__FILE__) . '/vendor/autoload.php');
require_once (ABSPATH . 'wp-includes/pluggable.php');


@@ -128,7 +127,7 @@ class AcareOffice{
$loader->register();
// Add our namespace and the folder it maps to
$loader->addNamespace('\XeroPHP', dirname(__FILE__) . '/xero-php-master/src/XeroPHP');
// $loader->addNamespace('\XeroPHP', dirname(__FILE__) . '/xero-php-master/src/XeroPHP');
$loader->addNamespace('\Biukop', dirname(__FILE__) . '/' );

@@ -1360,7 +1359,7 @@ ZOT;
'ratetype' => [],
);
$buddy = $xx->get_buddy_timesheets($staff_login, new \DateTime($start), new \DateTime($finish));
$buddy = $xx->get_buddy_timesheets($staff_login, $start, $finish);
if ($buddy != NULL){
$item['Xero_Status'] = $buddy->getStatus();
}else{
@@ -1537,7 +1536,7 @@ ZOT;
try{
$invoice = $this->create_invoice_by_client($client, $start, $finish);
$response['invoice_number'] = sprintf("<a href='https://go.xero.com/AccountsReceivable/Edit.aspx?InvoiceID=%s' target='_blank'>%s</a>",
$invoice->getInvoiceID(), $invoice->getInvoiceNumber());
$invoice->getInvoiceId(), $invoice->getInvoiceNumber());
}catch(\Exception $e){
$response['status'] = 'error';
$response['err'] = "XERO Invoice Error";
@@ -1559,22 +1558,23 @@ ZOT;
$sql = "SELECT * from $this->table_name WHERE tos != 1 and start>='$start 00:00:00' and start<='$finish 23:59:59' and client='$client_login' ORDER BY start";
$rows = $this->db->get_results($sql);
$xero = $this->xero->get_xero_handle();
$api = $this->XeroOauth2->get_accounting_instance();
//crate invoice
$invoice = new \XeroPHP\Models\Accounting\Invoice($xero);
$contact= $xero->loadByGUID('Accounting\\Contact', $client_login);
$invoice = new \XeroAPI\XeroPHP\Models\Accounting\Invoice;
$contacts = $api->getContact($this->XeroOauth2->getTenantId(), $client_login);
$now = new \DateTime();
$due = new \DateTime();
$due->modify("+14 days");
$invoice->setType("ACCREC")
->setStatus("DRAFT")
->setContact($contact)
->setDate($now)
->setDueDate($due);
$to_save=[];//all invoices to save;
$invoice->setType("ACCREC");
$invoice->setStatus("DRAFT");
$invoice->setContact($contacts[0]);
$invoice->setDate($now);
$invoice->setDueDate($due);
$price = new NdisPrice(2019);//always 2019 until its being changed;

$lineItems=[];
foreach($rows as $r){
$quantity = $this->get_job_hours($r->start, $r->finish);
$unit = $price->get_tos_unit($r->tos);
@@ -1584,18 +1584,24 @@ ZOT;
}
$unitprice = $price->get_tos_price($r->tos);
$description = $this->get_job_description_for_invoice($price, $r);
$lineItem = new \XeroPHP\Models\Accounting\Invoice\LineItem($xero);
$lineItem->setDescription($description)
->setQuantity($quantity)
->setUnitAmount($unitprice)
->setAccountCode(220)
->setTaxType("EXEMPTOUTPUT");
$invoice->addLineItem($lineItem);
$lineItem = new \XeroAPI\XeroPHP\Models\Accounting\LineItem;
$lineItem->setDescription($description);
$lineItem->setQuantity($quantity);
$lineItem->setUnitAmount($unitprice);
$lineItem->setAccountCode(220);
$lineItem->setTaxType("EXEMPTOUTPUT");
$lineItems[]= $lineItem;
}
$invoice->setLineItems($lineItems);
//prevent zero lineitems
if ( count($invoice->getLineItems()) >0 )
$invoice->save();
if ( count($invoice->getLineItems()) >0 ){
$to_save[] = $invoice;
$invoices = new \XeroAPI\XeroPHP\Models\Accounting\Invoices;
$invoices->setInvoices($to_save);
$result = $api->createInvoices($this->XeroOauth2->getTenantId(), $invoices);
$createdInvoices = $result->getInvoices();
return $createdInvoices[0];
}
return $invoice;
}

Loading…
취소
저장