Git Product home page Git Product logo

bizcuit-bexio's Introduction

BizCuit-Bexio, bexio API in PHP

This library allow to access Bexio API. Constructed arround cURL, it uses token authentication and provide a great deal of features.

It abastracts between the differents API version (like 4 in 4 years is quite a lot) to make every endpoint look the same. It relies on class composition to achieve that, example :

class BexioContact extends BexioAPI {
	protected $type = 'contact';
	protected $class = 'BizCuit\BXObject\Contact';
	protected $query = 'BizCuit\BXQuery\Contact';


	use tBexioV2Api, tBexioObject, tBexioCollection;
}

Still in active developpement, it also provide tooling to build a data cache short term (to mitigate Rate Limiting) and long term to keep working (read-only) if the upstream service goes down.

Endorsement

The fact that I am developping this doesn't mean that I endorse Bexio product. I do it because I need it, but if I were to have the choice, I wouldn't use bexio. The support is quite arrogant and try as hard as possible to drive away dev like me, the application is soooooo slow (to get ONE item through the API, you wait 500ms, even from the official frontend you spend more time waiting than working) and it is expensive.

Install

Via composer composer require "artnum/bizcuit-bexio @dev"

Documentation

Documentation available at https://bizcuit.ch

Example of usage

$context = new BizCuit\BexioCTX($bexio_api_token);

$bills = new BizCuit\BexioBills($context);
$files = new BizCuit\BexioFile($context);

$billQuery = $bills->newQuery();
$billQuery->add('status', 'DRAFT');

$billInDraft = $bills->search($billQuery);
foreach($billInDraft as $bill) {
    foreach($bill->attachment_ids as $fileUUID) {
        $fileWithContent = $file->get($fileUUID);
    }
}

Available Classes

Each class represents an endpoint, adding more classes is quite easy, I just didn't take the time and will add them as I use them.

  • BexioCountry
  • BexioQuote
  • BexioInvoice
  • BexioOrder
  • BexioContact
  • BexioProject
  • BexioContactRelation
  • BexioAdditionalAddress
  • BexioNote
  • BexioUser
  • BexioBusinessActivity
  • BexioSalutation
  • BexioTitle
  • BexioProjectType
  • BexioProjectStatus
  • BexioBills
  • BexioFile

Create new class for endpoint

To add a read-only class, you can define it with ROObject like, for example, BexioProjectStatus :

class BexioProjectStatus extends BexioAPI {
	protected $type = 'pr_project_state';
	protected $class = 'BizCuit\BXObject\ROObject';
	protected $query = 'BizCuit\BXQuery\ROObject';

	use tBexioV2Api, tBexioObject, tBexioCollection;
}

In order to create a full class, you would need to define an object class and a query class (but you can still have a query class ROObject with an object class of the full type), like BexioContact (choosen because this hits a bug in the API and, as the last phone call I had with the company : "the API is not strategic", meaning that they don't really care about that).

/* file bxobject.php */
class Contact extends BXObject {
    const NR = null;
    const createProperties = [
        'nr',
        'contact_type_id',
        'name_1',
        'name_2',
        'salutation_id',
        'salutation_form',
        'titel_id',
        'birthday',
        'address',
        'postcode',
        'city',
        'country_id',
        'mail',
        'mail_second',
        'phone_fixed',
        'phone_fixed_second',
        'phone_mobile',
        'fax',
        'url',
        'skype_name',
        'remarks',
        'language_id',
        'contact_group_ids',
        'contact_branch_ids',
        'user_id',
        'owner_id'
    ];

    /* API BUG when requesting a contact, if no salutation are set, the result
     * will have salutation_id = 0, but when sending back to update, edit or
     * replace the contact, the server complains with this value not being to
     * "null", so this is to fix that.
     */
    const nullableProperties = [
        'salutation_id'
    ];
}

/* file bxquery.php */
class Contact extends BXQuery {
	function __construct() {
		parent::__construct([
			'id',
			'name_1',
			'name_2',
			'nr',
			'address',
			'mail',
			'mail_second',
			'postcode',
			'city',
			'country_id',
			'contact_group_ids',
			'contact_type_id',
			'updated_at',
			'user_id',
			'phone_fixed',
			'phone_mobile',
			'fax'
		]);
	}
}

/* file bexio.php */
class BexioContact extends BexioAPI {
	protected $type = 'contact';
	protected $class = 'BizCuit\BXObject\Contact';
	protected $query = 'BizCuit\BXQuery\Contact';


	use tBexioV2Api, tBexioObject, tBexioCollection;
}

Available trait for class composition

tBexioObject

  • function new ():BXObject (create a new object of this type)
  • function delete(Int|String|BXObject $id): Bool (delete object)
  • function get (Int|String|BXObject $id, array $options = []):BXObject (get the object)
  • function set (BXObject $content):BXObject|false (save an object)
  • function update (BXObject $content):BXObject|false (update an object)

tBexioCollection

  • function getIdName ():string (get the name of the property used as id for this collection)
  • function newQuery ():BXquery (prepare a query object for this collection)
  • function search (BXQuery $query, Int $offset = 0, Int $limit = 500):array (execute a search on the collection)
  • function list (Int $offset = 0, Int $limit = 500):array (list collection)

tBexioV2Api, tBexioV3Api and tBexioV4Api

Used only to set the right API number

tBexioArchiveable

  • function archive (BXObject $content):bool (archive an object)
  • function unarchive (BXObject $content):bool (unarchive an object)

tBexioNumberObject

  • function getByNumber (Int|String $id):BXObject (get an object by its number instead of id)

tBexioPDFObject

  • function getPDF(Int|BXObject $id):BXObject (get a PDF of the object)

tBexioProjectObject

  • function listByProject (Int|BXObject $projectId): Array (List by project id)

bizcuit-bexio's People

Contributors

araeubig avatar artnum avatar

Watchers

 avatar  avatar  avatar

Forkers

araeubig

bizcuit-bexio's Issues

Searching for contacts only with name and prename results in error

I tried searching for contacts only with name and prename gives me an error:

$contactQuery = $bxcontact->newQuery();
$contactQuery->add( 'name1', $data['name'] );
$contactQuery->add( 'name2', $data['prename'] );
// $contactQuery->add( 'address', $data['address'] );
// $contactQuery->add( 'postcode', $data['postcode'] );
// $contactQuery->add( 'city', $data['city'] );
$contactQuery->add( 'phone_mobile', $data['mobile'], 'like' );
$contact = $bxcontact->search( $contactQuery );

uncommenting city works. I try to test against existing contacts but this only for your information.

Diving into the classes and trying to use ContactGroups

I need only a small hint to search in ContactGroups before adding "wrong" code. I saw that ContactGroups exist with ROOObject but with the normal: $bxcontactgroup = new BizCuit\BexioContactGroup($bxCtx); it doesn't work.

BexioQuote: get doesn't work

$bxquote = new BizCuit\BexioQuote($bxCtx);
$id = 5;
$quote = $bxquote->get($id);

It runs into:
Fatal error: Uncaught Exception: {"error_code":415,"message":"Could not parse the data."} in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:153 Stack trace: #0 /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php(217): BizCuit\BexioCTX->handle_result('{"error_code":4...', 415, 'application/jso...') #1 /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php(497): BizCuit\BexioCTX->fetch() #2 /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php(175): BizCuit\BexioQuote->get(5) #3 {main} Next Exception: The data could not be processed or the accept header is invalid in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 153 Exception: The data could not be processed or the accept header is invalid in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 153 Call Stack: 0.0004 487048 1. {main}() /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php:0 0.2435 604824 2. BizCuit\BexioQuote->get($id = 5, $options = ???) /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php:175 0.2435 604960 3. BizCuit\BexioCTX->fetch() /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:497 0.3802 601344 4. BizCuit\BexioCTX->handle_result($data = '{"error_code":415,"message":"Could not parse the data."}', $code = 415, $type = 'application/json') /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:217 Nested Exceptions: Exception: {"error_code":415,"message":"Could not parse the data."} in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 153 Call Stack: The stack is empty or not available

Some collected questions or only one example required

Hello and thanks for writing via WhatsApp.

To understand your way of doing the things it would be great to get some examples by you. The examples shouldn't be detailed the normal working code would even help.

  • Getting a contact by ID
  • Add a contact
  • Add a quote
  • Edit a quote

I think with these three examples i could translate it to allmost all required uses. But if you have more it would be absolutely great. What i can offer is to extend with pull requests all new things which i had to build and to help documenting.

My target is to build a configurable workflow from "calenso"->"bexio" and from "bexio"<->"stripe terminal for POS". In a second step a connect from a "standalone cardterminal"<->"bexio".

I have read your annotation about the bexio behavior and you are absolutely right. Actually i started opening one ticket for each inadequacy or bug.

Regards André and it would be great to ready by you.

Error in using "list()" with BexioSalutation

I tried using "list()" with 'BexioSalutation' but it gives my following error:

Fatal error: Uncaught Exception: {"error_code":400,"message":"The following order parameters could not have been applied: ","errors":["id"]} in /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php:148 Stack trace: #0 /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php(217): BizCuit\BexioCTX->handle_result('{"error_code":4...', 400, 'application/jso...') #1 /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php(445): BizCuit\BexioCTX->fetch() #2 /workspaces/bexio-POS-App/www/contacts.php(16): BizCuit\BexioSalutation->list() #3 {main} Next Exception: The request parameters are invalid in /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php:148 Stack trace: #0 /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php(217): BizCuit\BexioCTX->handle_result('{"error_code":4...', 400, 'application/jso...') #1 /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php(445): BizCuit\BexioCTX->fetch() #2 /workspaces/bexio-POS-App/www/contacts.php(16): BizCuit\BexioSalutation->list() #3 {main} thrown in /workspaces/bexio-POS-App/www/vendor/artnum/bizcuit-bexio/bexio.php on line 148

I used basic "list()" without any parameters.

For
'BexioTitle'
'BexioCountry'
'BexioContactGroup'
'BexioContact'

it works perfect.

Avoid duplicated contacts

It would be great to use an automatically function like:

add contact (duplicate: no; merge: yes)

The contact would be added only if it doesn't exist and id new contact details are given they are merged into the original one.
Only an idea for integration.

Your function toJson ......

I think your embedded functions are used for the communication with the API. Is that right? Actually i try to convert the result of a "list"- and "search"-query to reduced JSON.

Error on creating quote

I tested with starting my planned document workflow and logical way through bexio by creating at first:

  • a quote: and run into an error (added at the bottom here) that i need a project id - based on bexio API documentation the project id is not needed. In my workflow logic i haven't a project id because i create the project based on the first quote. if i add a project id for testing it works.

my code:

$bxCtx = new BizCuit\BexioCTX($bexio_api_token);

$bxquote = new BizCuit\BexioQuote($bxCtx);

$object = $bxquote->new();

$object->title = "test quote";
$object->contact_id = "8";
$object->user_id = "1";
//$object->project_id = "8";
$object->mwst_is_net = true;

$ret = $bxquote->set($object);

my errror without project_id:
Fatal error: Uncaught Exception: {"error_code":422,"message":"The form could not be saved due to the following errors:","errors":["global: Unexpected extra form field named \"project_id\"."]} in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:154 Stack trace: #0 /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php(217): BizCuit\BexioCTX->handle_result('{"error_code":4...', 422, 'application/jso...') #1 /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php(536): BizCuit\BexioCTX->fetch() #2 /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php(18): BizCuit\BexioQuote->set(Object(BizCuit\BXObject\Quote)) #3 {main} Next Exception: Could not save the entity in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 154 Exception: Could not save the entity in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 154 Call Stack: 0.0003 479688 1. {main}() /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php:0 0.0008 586456 2. BizCuit\BexioQuote->set($content = class BizCuit\BXObject\Quote { protected $changes = [0 => 'title', 1 => 'contact_id', 2 => 'user_id', 3 => 'mwst_is_net']; protected $content = class stdClass { public $title = 'test neu 2'; public $contact_id = '8'; public $contact_sub_id = NULL; public $user_id = '1'; public $project_id = NULL; public $language_id = NULL; public $bank_account_id = NULL; public $currency_id = NULL; public $payment_type_id = NULL; public $header = NULL; public $footer = NULL; public $mwst_type = NULL; public $mwst_is_net = TRUE; public $show_position_taxes = NULL; public $is_valid_from = NULL; public $is_valid_until = NULL; public $delivery_address_type = NULL; public $api_reference = NULL; public $viewed_by_client_at = NULL; public $kb_terms_of_payment_template_id = NULL; public $template_slug = NULL; public $positions = NULL } }) /workspaces/bexio-stripe-pos-backend/www/bexio-v1/new.php:18 0.0008 587104 3. BizCuit\BexioCTX->fetch() /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:536 0.2167 588440 4. BizCuit\BexioCTX->handle_result($data = '{"error_code":422,"message":"The form could not be saved due to the following errors:","errors":["global: Unexpected extra form field named \\"project_id\\"."]}', $code = 422, $type = 'application/json') /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php:217 Nested Exceptions: Exception: {"error_code":422,"message":"The form could not be saved due to the following errors:","errors":["global: Unexpected extra form field named \"project_id\"."]} in /workspaces/bexio-stripe-pos-backend/www/vendor/artnum/bizcuit-bexio/bexio.php on line 154 Call Stack: The stack is empty or not available

Missing sample

I have read through your repo and started reading your documentation. My first thoughts are, that you made a great extendable work -> this is really sustainable. But i'm missing a more detailed simple example including the authentication - i mean a working example would be perfect.

Regards André

Trying to get a contact by ID

Sorry for disturbing you again:

I have actually no chance to get a contact by ID. The list of contacts works perfect but the "get" doesn't work -> I think that my approach is not correct:

$context = new BizCuit\BexioCTX($bexio_api_token);

$invoices = new BizCuit\BexioInvoice($context);
$contacts = new BizCuit\BexioContact($context);

$invoicesQuery = $invoices->newQuery();
$invoicesQuery->add('kb_item_status_id', '8');

$invoicesPending = $invoices->search($invoicesQuery);
foreach($invoicesPending as $invoice) {
    $client = $invoice->contact_id;
    $contact = $contacts->get($client);
}

It would be great to get a small hint.

Regards André and a happy Sunday from Basel.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.