<?php
// src/Service/UserService.php
namespace App\Service\Xero;
use App\Entity\FilmProject;
use App\Entity\OrderDetails;
use App\Entity\User;
use App\Authenticator\XeroAuthenticator;
use App\Repository\UserRepository;
use App\Service\Xero\XeroService;
use Exception;
use XeroAPI\XeroPHP\Models\Accounting\Contact;
use XeroAPI\XeroPHP\Models\Accounting\ContactPerson;
use XeroAPI\XeroPHP\Models\Accounting\Contacts;
use XeroAPI\XeroPHP\ApiException;
use XeroAPI\XeroPHP\Models\Accounting\Address;
final class ContactService extends XeroService
{
private $userRepository;
public function __construct(XeroAuthenticator $xeroAuthenticator, UserRepository $userRepository)
{
parent::__construct($xeroAuthenticator);
$this->userRepository = $userRepository;
}
/**
* Create Xero contact
*
* @param User $user
* @return string
*/
public function createContact(User $user): string
{
// Check if contact is already registered in the system
$xeroID = $this->getContactByUser($user);
if (!empty($xeroID)) {
return $xeroID;
}
$contact = new Contact;
$contact->setName($user->getFirstName() . ' ' . $user->getLastName())
->setFirstName($user->getFirstName())
->setLastName($user->getLastName())
->setEmailAddress($user->getEmail())
;
if ($user->getUserAddress()) {
$userAddress = $user->getUserAddress();
$address = new Address();
$address->setAddressType(Address::ADDRESS_TYPE_STREET);
if ($userAddress->getStreet()) $address->setAddressLine1($userAddress->getStreet());
if ($userAddress->getCity()) $address->setCity($userAddress->getCity());
if ($userAddress->getState()) $address->setRegion($userAddress->getState());
if ($userAddress->getPostcode()) $address->setPostalCode($userAddress->getPostcode());
if ($userAddress->getCountry()) $address->setCountry($userAddress->getCountry());
$arr_addresses = [];
array_push($arr_addresses, $address);
$contact->setAddresses($arr_addresses);
}
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->createContacts($this->xeroTenantId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Create Xero contact
*
* @param User $user
* @return string
*/
public function createContactByProjectName(FilmProject $filmProject): string
{
$contact = new Contact;
$user = $filmProject->getOwner();
$contact->setName($filmProject->getTitle()) // Unique name here
->setFirstName($user->getFirstName())
->setLastName($user->getLastName())
->setEmailAddress($user->getEmail())
;
if ($user->getUserAddress()) {
$userAddress = $user->getUserAddress();
$address = new Address();
$address->setAddressType(Address::ADDRESS_TYPE_STREET);
if ($userAddress->getStreet()) $address->setAddressLine1($userAddress->getStreet());
if ($userAddress->getCity()) $address->setCity($userAddress->getCity());
if ($userAddress->getState()) $address->setRegion($userAddress->getState());
if ($userAddress->getPostcode()) $address->setPostalCode($userAddress->getPostcode());
if ($userAddress->getCountry()) $address->setCountry($userAddress->getCountry());
$arr_addresses = [];
array_push($arr_addresses, $address);
$contact->setAddresses($arr_addresses);
}
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->createContacts($this->xeroTenantId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Update contact
*
* @param User $user
* @return void
*/
public function updateContact(User $user)
{
$userInformation = $user->getUserInformation();
$userAddress = $user->getUserAddress();
$xeroContactId = $userInformation->getXeroId();
$arr_addresses = [];
$address = (new Address())
->setAddressType(Address::ADDRESS_TYPE_STREET)
->setAddressLine1($userAddress->getStreet())
->setCity($userAddress->getCity())
->setPostalCode($userAddress->getPostcode())
;
array_push($arr_addresses, $address);
$contact = new Contact();
$contact
->setName($user->getFirstName() . ' ' . $user->getLastName())
->setFirstName($user->getFirstName())
->setLastName($user->getLastName())
->setContactID($xeroContactId)
->setAddresses($arr_addresses)
;
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->updateContact($this->xeroTenantId, $xeroContactId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Get contacts by email
*
* @param [type] $fullname
* @return string
*/
public function getContactByUser(User $user): ?string
{
$fullName = $user->getFirstName() . ' ' . $user->getLastName();
/** This represents paramater needed for Xero getContacts */
$modifiedSince = new \DateTime('2010-01-01');
$where = 'ContactStatus=="' . Contact::CONTACT_STATUS_ACTIVE . '"';
$order = "Name ASC";
$page = 1;
$searchTerm = $user->getEmail();
$includeArchived = true;
$summaryOnly = true;
$contacts = $this->xeroAccountingManager->getContacts($this->xeroTenantId, $modifiedSince, $where, $order, null, $page, $includeArchived, $summaryOnly, $searchTerm);
foreach ($contacts as $contact) {
if (strtolower($contact['name']) == strtolower($fullName)) {
return $contact['contact_id'];
}
}
return null;
}
/**
* Get contacts by email
*
* @param [type] $fullname
* @return string
*/
public function getContactByEmail(string $email): ?string
{
/** This represents paramater needed for Xero getContacts */
$modifiedSince = new \DateTime('2010-01-01');
$where = 'ContactStatus=="' . Contact::CONTACT_STATUS_ACTIVE . '"';
$order = "Name ASC";
$page = 1;
$searchTerm = $email;
$includeArchived = true;
$summaryOnly = true;
$contacts = $this->xeroAccountingManager->getContacts($this->xeroTenantId, $modifiedSince, $where, $order, null, $page, $includeArchived, $summaryOnly, $searchTerm);
foreach ($contacts as $contact) {
if ($contact['email_address'] == $email) {
return $contact['contact_id'];
}
}
return null;
}
/**
* Get contacts by id
*
* @param [type] $fullname
* @return obj
*/
public function getContactById(string $contactId)
{
try {
$contacts = $this->xeroAccountingManager->getContact($this->xeroTenantId, $contactId);
}
catch (Exception $e) {
$this->throwExceptionMessage($e->getMessage());
}
if ($contacts) {
return $contacts[0];
}
return null;
}
/**
* Get contacts by name
*
* @param [type] $fullname
* @return string
*/
public function getContactByOrderDetails(OrderDetails $orderDetails): ?string
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$user = $this->userRepository->findOneBy(['email' => $orderBillingDetails->getEmailAddress()]);
$fullName = $orderBillingDetails->getFirstName() .' '. $orderBillingDetails->getLastName();
// TODO: ENABLED when client agree to use the same ID for the same contact integrated with the system
// if ($user) {
// $fullName = $user->getFirstName() .' '. $user->getLastName() . ' - ' . $user->getId();
// $userInformation = $user->getUserInformation();
// return $userInformation->getXeroId();
// }
/** This represents paramater needed for Xero getContacts */
$modifiedSince = new \DateTime('2020-01-01');
$where = 'ContactStatus=="' . Contact::CONTACT_STATUS_ACTIVE . '"';
$order = "Name ASC";
$page = 1;
// $searchTerm = $fullName;
$searchTerm = $orderBillingDetails->getEmailAddress();
$includeArchived = true;
$summaryOnly = true;
$contacts = $this->xeroAccountingManager->getContacts($this->xeroTenantId, $modifiedSince, $where, $order, null, $page, $includeArchived, $summaryOnly, $searchTerm);
foreach ($contacts as $contact) {
// if (strtolower($contact['name']) == strtolower($fullName)) {
if (str_contains(strtolower($contact['name']),strtolower($fullName) )) {
return $contact['contact_id'];
}
}
return null;
}
/**
* Create Xero contact
*
* @param User $user
* @return string
*/
public function createContactByOrderDetails(OrderDetails $orderDetails): string
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$contact = new Contact;
$contact->setName($orderBillingDetails->getFirstName() . ' ' . $orderBillingDetails->getLastName() . ' - '. $orderDetails->getId())
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
->setEmailAddress($orderBillingDetails->getEmailAddress());
$address = new Address();
$address->setAddressType(Address::ADDRESS_TYPE_POBOX);
if ($orderBillingDetails->getStreet()) $address->setAddressLine1($orderBillingDetails->getStreet());
if ($orderBillingDetails->getSuburb()) $address->setCity($orderBillingDetails->getSuburb());
if ($orderBillingDetails->getState()) $address->setRegion($orderBillingDetails->getState());
if ($orderBillingDetails->getPostcode()) $address->setPostalCode($orderBillingDetails->getPostcode());
if ($orderBillingDetails->getCountry()) $address->setCountry($orderBillingDetails->getCountry());
$arr_addresses = [];
array_push($arr_addresses, $address);
$contact->setAddresses($arr_addresses);
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->createContacts($this->xeroTenantId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Create Xero contact
*
* @param User $user
* @return string
*/
public function createGuestContactByOrderDetails(OrderDetails $orderDetails): string
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$contact = new Contact;
$contact->setName($orderBillingDetails->getFirstName() . ' ' . $orderBillingDetails->getLastName())
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
->setEmailAddress($orderBillingDetails->getEmailAddress());
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->createContacts($this->xeroTenantId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Update Xero contact details
*
* @param OrderDetails $orderDetails
* @param [type] $xeroContactId
* @return void
*/
public function updateContactByOrderDetails(OrderDetails $orderDetails, $xeroContactId)
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$contact = new Contact();
$contact
// ->setName($orderBillingDetails->getFirstName() . ' ' . $orderBillingDetails->getLastName())
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
->setEmailAddress($orderBillingDetails->getEmailAddress())
->setContactID($xeroContactId)
// TODO: set other fields such as address
;
$address = new Address();
$address->setAddressType(Address::ADDRESS_TYPE_POBOX);
if ($orderBillingDetails->getStreet()) $address->setAddressLine1($orderBillingDetails->getStreet());
if ($orderBillingDetails->getSuburb()) $address->setCity($orderBillingDetails->getSuburb());
if ($orderBillingDetails->getState()) $address->setRegion($orderBillingDetails->getState());
if ($orderBillingDetails->getPostcode()) $address->setPostalCode($orderBillingDetails->getPostcode());
if ($orderBillingDetails->getCountry()) $address->setCountry($orderBillingDetails->getCountry());
$arr_addresses = [];
array_push($arr_addresses, $address);
$contact->setAddresses($arr_addresses);
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->updateContact($this->xeroTenantId, $xeroContactId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Check if contact exists on current XERO contact Id
*
* @param [type] $contactId
* @return void
*/
public function checkContactExists($xeroContactId) {
$isExist = false;
try {
$apiResponse = $this->xeroAccountingManager->getContact($this->xeroTenantId, $xeroContactId);
} catch (ApiException $e) {
return $isExist;
}
if (!$apiResponse[0]['HasValidationErrors']) {
$isExist = true;
}
return $isExist;
}
/**
* Update contact
*
* @param OrderDetails $orderDetails
* @param string $xeroContactId
* @return void
*/
public function updateContactById(OrderDetails $orderDetails, string $xeroContactId)
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$contact = new Contact();
$contact
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
;
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->updateContact($this->xeroTenantId, $xeroContactId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Get contacts by organisation name
*
* @param OrderDetails $orderDetails
* @return string
*/
public function getContactOrganisationByOrderDetails(OrderDetails $orderDetails): ?string
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$fullName = $orderBillingDetails->getOrganisation();
/** This represents paramater needed for Xero getContacts */
$modifiedSince = new \DateTime('2020-01-01');
$where = 'ContactStatus=="' . Contact::CONTACT_STATUS_ACTIVE . '"';
$order = "Name ASC";
$page = 1;
$searchTerm = $fullName;
// $searchTerm = $orderBillingDetails->getEmailAddress();
$includeArchived = true;
$summaryOnly = true;
$contacts = $this->xeroAccountingManager->getContacts($this->xeroTenantId, $modifiedSince, $where, $order, null, $page, $includeArchived, $summaryOnly, $searchTerm);
foreach ($contacts as $contact) { // Make sure that the actual name is exactly the same as the search results
if (strtolower($contact['name']) == strtolower($fullName)) {
return $contact['contact_id'];
}
}
return null;
}
/**
* Create Xero contact with organisation name
*
* @param User $user
* @return string
*/
public function createContactOrganisationByOrderDetails(OrderDetails $orderDetails): string
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
$contact = new Contact;
$contact->setName($orderBillingDetails->getOrganisation())
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
->setEmailAddress($orderBillingDetails->getEmailAddress());
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
$apiResponse = $this->xeroAccountingManager->createContacts($this->xeroTenantId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
/**
* Gets all the additional persons from the contact based on XERO ID
*
* @param string $xeroID
* @return void|arr
*/
private function getOrganisationAdditionalPersonByXeroId(string $xeroID)
{
$result = [];
$contact = $this->getContactById($xeroID);
if (!empty($contact['contact_persons'])) {
return $contact['contact_persons'];
}
return $result;
}
/**
* Adds a new person as an additional person in the contact
*
* @param OrderDetails $orderDetails
* @param [type] $xeroContactId
* @return void
*/
public function updateOrganisationWithAdditionalPersonByOrderDetails(OrderDetails $orderDetails, $xeroContactId)
{
$orderBillingDetails = $orderDetails->getOrderBillingDetails();
// Check if the order billing details already exists as one of the additional person arr
$additionalPersonsArr = $this->getOrganisationAdditionalPersonByXeroId($xeroContactId);
$isExist = false;
foreach ($additionalPersonsArr as $personArr) {
if ($orderBillingDetails->getFirstName() == $personArr->getFirstName() && $orderBillingDetails->getLastName() == $personArr->getLastName() && $orderBillingDetails->getEmailAddress() == $personArr->getEmailAddress()) {
$isExist = true;
break;
}
}
if ($isExist) { // If alreadt exist, dont update anything
return null;
}
$person = new ContactPerson;
$person
->setFirstName($orderBillingDetails->getFirstName())
->setLastName($orderBillingDetails->getLastName())
->setEmailAddress($orderBillingDetails->getEmailAddress())
->setIncludeInEmails(false)
;
array_push($additionalPersonsArr, $person);
$contact = new Contact;
$contact
->setContactPersons($additionalPersonsArr)
;
$arr_contacts = [];
array_push($arr_contacts, $contact);
$contacts = new Contacts;
$contacts->setContacts($arr_contacts);
// Update the organisation contact
$apiResponse = $this->xeroAccountingManager->updateContact($this->xeroTenantId, $xeroContactId, $contacts);
if ($apiResponse[0]['has_validation_errors']) {
$this->throwExceptionMessage($apiResponse[0]['validation_errors'][0]['message']);
}
return $apiResponse[0]['contact_id'];
}
}