From 76ca5827655087053829b88a31ca20437a5ddf75 Mon Sep 17 00:00:00 2001 From: Loduis Madariaga Date: Sat, 11 Jan 2025 11:20:20 -0500 Subject: [PATCH] feat: add invoices. --- src/Currency.php | 19 + src/Expense.php | 3 + src/Invoice.php | 35 + src/Rest/Resource/schemas/invoices.json | 26 + src/Rest/Response/JSON.php | 6 + tests/CurrencyTest.php | 13 + tests/InvoiceTest.php | 96 +++ ...ceTest__testCreate with data set 0__1.json | 7 + tests/bootstrap.php | 4 +- tests/fixtures/currencycodes.json | 681 ++++++++++++++++++ tests/fixtures/invoices.json | 38 + tests/fixtures/invoices/128550.json | 35 + tests/fixtures/projects/967489/invoices.json | 38 + 13 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 src/Currency.php create mode 100644 src/Invoice.php create mode 100644 src/Rest/Resource/schemas/invoices.json create mode 100644 tests/CurrencyTest.php create mode 100644 tests/InvoiceTest.php create mode 100644 tests/__snapshots__/InvoiceTest__testCreate with data set 0__1.json create mode 100644 tests/fixtures/currencycodes.json create mode 100644 tests/fixtures/invoices.json create mode 100644 tests/fixtures/invoices/128550.json create mode 100644 tests/fixtures/projects/967489/invoices.json diff --git a/src/Currency.php b/src/Currency.php new file mode 100644 index 0000000..006547a --- /dev/null +++ b/src/Currency.php @@ -0,0 +1,19 @@ +notUseFields() + ->put("$this->action/$id/lineitems", [ + 'lineitems' => [ + 'add' => [ + 'timelogs' => "$time" + ] + ] + ]); + } +} diff --git a/src/Rest/Resource/schemas/invoices.json b/src/Rest/Resource/schemas/invoices.json new file mode 100644 index 0000000..4fa25f4 --- /dev/null +++ b/src/Rest/Resource/schemas/invoices.json @@ -0,0 +1,26 @@ +{ + "description": { + "type": "string" + }, + "fixed_cost": { + "type": "string", + "transform": "dash" + }, + "number": { + "type": "string", + "required": true + }, + "po_number": { + "type": "string", + "transform": "dash" + }, + "display_date": { + "type": "string", + "transform": "dash", + "required": true + }, + "currency_code": { + "type": "string", + "transform": "dash" + } +} \ No newline at end of file diff --git a/src/Rest/Response/JSON.php b/src/Rest/Response/JSON.php index ebf9437..82e9d86 100755 --- a/src/Rest/Response/JSON.php +++ b/src/Rest/Response/JSON.php @@ -31,6 +31,12 @@ public function parse(string $data, array $headers): static | int | bool | strin ] = $headers; if (!in_array($status, [200, 201, 204])) { + if ($status === 500 && isset($source['content'])) { + $source = $source['content']; + if (isset($source['errors']) && is_array($source['errors'])) { + $source['error'] = implode(PHP_EOL, $source['errors']); + } + } $errors = $source['MESSAGE'] ?? $source['error'] ?? $errors ?? "Unknown error ($status) status"; } if ($errors !== null) { diff --git a/tests/CurrencyTest.php b/tests/CurrencyTest.php new file mode 100644 index 0000000..2e3462a --- /dev/null +++ b/tests/CurrencyTest.php @@ -0,0 +1,13 @@ +assertGreaterThan(0, count($this->factory('currency', [ + 'GET /currencycodes' => true + ])->all())); + } +} \ No newline at end of file diff --git a/tests/InvoiceTest.php b/tests/InvoiceTest.php new file mode 100644 index 0000000..1692a84 --- /dev/null +++ b/tests/InvoiceTest.php @@ -0,0 +1,96 @@ +assertEquals(TPM_TEST_ID, $this->factory('invoice', [ + 'POST /projects/' . TPM_PROJECT_ID_1 . '/invoices' => fn($data) => $this->assertMatchesJsonSnapshot($data) + ])->create($data)); + } + + public function testAll(): void + { + $this->assertGreaterThan(0, count($this->factory('invoice', [ + 'GET /invoices' => true + ])->all())); + } + + public function testGetByProject(): void + { + $this->assertGreaterThan(0, count($this->factory('invoice', [ + 'GET /projects/' . TPM_PROJECT_ID_1 . '/invoices' => true + ])->getByProject(TPM_PROJECT_ID_1))); + } + + public function testGet(): void + { + $this->assertEquals('USD', $this->factory('invoice', [ + 'GET /invoices/' . TPM_INVOICE_ID => true + ])->get(TPM_INVOICE_ID)->currencyCode); + } + + /** + * @dataProvider provider + */ + public function testUpdate(array $data): void + { + $data['id'] = TPM_INVOICE_ID; + $data['description'] = 'Updated Invoice Description'; + $this->assertTrue($this->factory('invoice', [ + 'PUT /invoices/' . TPM_INVOICE_ID => true + ])->update($data)); + } + + public function testComplete(): void + { + $this->assertTrue($this->factory('invoice', [ + 'PUT /invoices/' . TPM_INVOICE_ID . '/complete' => true + ])->complete(TPM_INVOICE_ID)); + } + + public function testUnComplete(): void + { + $this->assertTrue($this->factory('invoice', [ + 'PUT /invoices/' . TPM_INVOICE_ID . '/uncomplete' => true + ])->unComplete(TPM_INVOICE_ID)); + } + + /** + * @todo This test fail on real api + * + * @return void + */ + public function testAddTime(): void + { + $this->assertTrue($this->factory('invoice', [ + 'PUT /invoices/' . TPM_INVOICE_ID . '/lineitems' => true + ])->addTime(TPM_INVOICE_ID, '10 hours')); + } + + public function testDelete(): void + { + $this->assertTrue($this->factory('invoice', [ + 'DELETE /invoices/' . TPM_INVOICE_ID => true + ])->delete(TPM_INVOICE_ID)); + } + + public function provider() + { + return [ + [ + [ + 'description' => 'Bla, Bla, Bla', + 'number' => 100, + 'project_id' => TPM_PROJECT_ID_1, + 'display_date' => '20250101' + ], + ], + ]; + } +} diff --git a/tests/__snapshots__/InvoiceTest__testCreate with data set 0__1.json b/tests/__snapshots__/InvoiceTest__testCreate with data set 0__1.json new file mode 100644 index 0000000..8bb9d71 --- /dev/null +++ b/tests/__snapshots__/InvoiceTest__testCreate with data set 0__1.json @@ -0,0 +1,7 @@ +{ + "invoice": { + "description": "Bla, Bla, Bla", + "number": "100", + "display-date": "20250101" + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 4b70612..76dae05 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -58,4 +58,6 @@ const TPM_PORTFOLIO_CARD_ID = 121235; -const TPM_EXPENSE_ID = 2757; \ No newline at end of file +const TPM_EXPENSE_ID = 2757; + +const TPM_INVOICE_ID = 128550; \ No newline at end of file diff --git a/tests/fixtures/currencycodes.json b/tests/fixtures/currencycodes.json new file mode 100644 index 0000000..2dba279 --- /dev/null +++ b/tests/fixtures/currencycodes.json @@ -0,0 +1,681 @@ +{ + "STATUS": "OK", + "currency-codes": [ + { + "code": "AFN", + "name": "Afghani" + }, + { + "code": "DZD", + "name": "Algerian dinar" + }, + { + "code": "ARS", + "name": "Argentine peso" + }, + { + "code": "AMD", + "name": "Armenian dram" + }, + { + "code": "AWG", + "name": "Aruban guilder" + }, + { + "code": "AUD", + "name": "Australian dollar" + }, + { + "code": "ATS", + "name": "Austria Schillings" + }, + { + "code": "AZN", + "name": "Azerbaijanian manat" + }, + { + "code": "BSD", + "name": "Bahamian dollar" + }, + { + "code": "BHD", + "name": "Bahraini dinar" + }, + { + "code": "THB", + "name": "Baht" + }, + { + "code": "PAB", + "name": "Balboa" + }, + { + "code": "BDT", + "name": "Bangladeshi taka" + }, + { + "code": "BBD", + "name": "Barbados dollar" + }, + { + "code": "BEF", + "name": "Belgium Francs" + }, + { + "code": "BZD", + "name": "Belize dollar" + }, + { + "code": "BMD", + "name": "Bermudian dollar" + }, + { + "code": "BOB", + "name": "Boliviano" + }, + { + "code": "BRL", + "name": "Brazilian real" + }, + { + "code": "BND", + "name": "Brunei dollar" + }, + { + "code": "BGL", + "name": "Bulgaria Leva" + }, + { + "code": "BGN", + "name": "Bulgarian lev" + }, + { + "code": "BIF", + "name": "Burundian franc" + }, + { + "code": "CAD", + "name": "Canadian dollar" + }, + { + "code": "CVE", + "name": "Cape Verde escudo" + }, + { + "code": "KYD", + "name": "Cayman Islands dollar" + }, + { + "code": "GHS", + "name": "Cedi" + }, + { + "code": "XOF", + "name": "CFA Franc BCEAO" + }, + { + "code": "XAF", + "name": "CFA franc BEAC" + }, + { + "code": "XPF", + "name": "CFP franc" + }, + { + "code": "CLP", + "name": "Chilean peso" + }, + { + "code": "RMB", + "name": "Chinese Renminbi Yuan" + }, + { + "code": "COP", + "name": "Colombian peso" + }, + { + "code": "KMF", + "name": "Comoro franc" + }, + { + "code": "BAM", + "name": "Convertible marks" + }, + { + "code": "NIO", + "name": "Cordoba oro" + }, + { + "code": "CRC", + "name": "Costa Rican colon" + }, + { + "code": "HRK", + "name": "Croatian kuna" + }, + { + "code": "CUP", + "name": "Cuban peso" + }, + { + "code": "CYP", + "name": "Cyprus Pounds" + }, + { + "code": "CZK", + "name": "Czech koruna" + }, + { + "code": "GMD", + "name": "Dalasi" + }, + { + "code": "DKK", + "name": "Danish krone" + }, + { + "code": "MKD", + "name": "Denar" + }, + { + "code": "DJF", + "name": "Djibouti franc" + }, + { + "code": "STD", + "name": "Dobra" + }, + { + "code": "DOP", + "name": "Dominican peso" + }, + { + "code": "XCD", + "name": "East Caribbean dollar" + }, + { + "code": "EGP", + "name": "Egyptian pound" + }, + { + "code": "ETB", + "name": "Ethiopian birr" + }, + { + "code": "EUR", + "name": "Euro" + }, + { + "code": "FKP", + "name": "Falkland Islands pound" + }, + { + "code": "FJD", + "name": "Fiji dollar" + }, + { + "code": "HUF", + "name": "Forint" + }, + { + "code": "CDF", + "name": "Franc Congolais" + }, + { + "code": "FRF", + "name": "France Francs" + }, + { + "code": "GIP", + "name": "Gibraltar pound" + }, + { + "code": "PYG", + "name": "Guarani" + }, + { + "code": "GNF", + "name": "Guinea franc" + }, + { + "code": "GYD", + "name": "Guyana dollar" + }, + { + "code": "HTG", + "name": "Haiti gourde" + }, + { + "code": "HKD", + "name": "Hong Kong dollar" + }, + { + "code": "UAH", + "name": "Hryvnia" + }, + { + "code": "ISK", + "name": "Iceland krona" + }, + { + "code": "INR", + "name": "Indian rupee" + }, + { + "code": "IRR", + "name": "Iranian rial" + }, + { + "code": "IQD", + "name": "Iraqi dinar" + }, + { + "code": "IEP", + "name": "Ireland Pounds" + }, + { + "code": "ITL", + "name": "Italy Lire" + }, + { + "code": "JMD", + "name": "Jamaican dollar" + }, + { + "code": "JPY", + "name": "Japanese yen" + }, + { + "code": "JOD", + "name": "Jordanian dinar" + }, + { + "code": "KZT", + "name": "Kazakhstani Tenge" + }, + { + "code": "KES", + "name": "Kenyan shilling" + }, + { + "code": "PGK", + "name": "Kina" + }, + { + "code": "LAK", + "name": "Kip" + }, + { + "code": "EEK", + "name": "Kroon" + }, + { + "code": "KWD", + "name": "Kuwaiti dinar" + }, + { + "code": "MWK", + "name": "Kwacha" + }, + { + "code": "ZMK", + "name": "Kwacha" + }, + { + "code": "AOA", + "name": "Kwanza" + }, + { + "code": "GEL", + "name": "Lari" + }, + { + "code": "LVL", + "name": "Latvian lats" + }, + { + "code": "LBP", + "name": "Lebanese pound" + }, + { + "code": "ALL", + "name": "Lek" + }, + { + "code": "HNL", + "name": "Lempira" + }, + { + "code": "SLL", + "name": "Leone" + }, + { + "code": "LRD", + "name": "Liberian dollar" + }, + { + "code": "LYD", + "name": "Libyan dinar" + }, + { + "code": "SZL", + "name": "Lilangeni" + }, + { + "code": "LTL", + "name": "Lithuanian litas" + }, + { + "code": "LSL", + "name": "Loti" + }, + { + "code": "LUF", + "name": "Luxembourg Francs" + }, + { + "code": "MGA", + "name": "Malagasy ariary" + }, + { + "code": "MYR", + "name": "Malaysian ringgit" + }, + { + "code": "MLT", + "name": "Maltese Lira" + }, + { + "code": "TMM", + "name": "Manat" + }, + { + "code": "MUR", + "name": "Mauritius rupee" + }, + { + "code": "MZN", + "name": "Metical" + }, + { + "code": "MXN", + "name": "Mexican peso" + }, + { + "code": "MDL", + "name": "Moldovan leu" + }, + { + "code": "MAD", + "name": "Moroccan dirham" + }, + { + "code": "NGN", + "name": "Naira" + }, + { + "code": "ERN", + "name": "Nakfa" + }, + { + "code": "NAD", + "name": "Namibian dollar" + }, + { + "code": "NPR", + "name": "Nepalese rupee" + }, + { + "code": "ANG", + "name": "Netherlands Antillian guilder" + }, + { + "code": "ILS", + "name": "New Israeli shekel" + }, + { + "code": "TWD", + "name": "New Taiwan dollar" + }, + { + "code": "NZD", + "name": "New Zealand dollar" + }, + { + "code": "BTN", + "name": "Ngultrum" + }, + { + "code": "KPW", + "name": "North Korean won" + }, + { + "code": "NOK", + "name": "Norwegian krone" + }, + { + "code": "PEN", + "name": "Nuevo sol" + }, + { + "code": "MRO", + "name": "Ouguiya" + }, + { + "code": "TOP", + "name": "Pa'anga" + }, + { + "code": "PKR", + "name": "Pakistan rupee" + }, + { + "code": "MOP", + "name": "Pataca" + }, + { + "code": "PHP", + "name": "Philippine peso" + }, + { + "code": "PTE", + "name": "Portugal Escudos" + }, + { + "code": "GBP", + "name": "Pound sterling" + }, + { + "code": "BWP", + "name": "Pula" + }, + { + "code": "QAR", + "name": "Qatari rial" + }, + { + "code": "GTQ", + "name": "Quetzal" + }, + { + "code": "CNY", + "name": "Renminbi" + }, + { + "code": "OMR", + "name": "Rial Omani" + }, + { + "code": "KHR", + "name": "Riel" + }, + { + "code": "ROL", + "name": "Romania Lei" + }, + { + "code": "RON", + "name": "Romanian new leu" + }, + { + "code": "MVR", + "name": "Rufiyaa" + }, + { + "code": "IDR", + "name": "Rupiah" + }, + { + "code": "RUB", + "name": "Russian ruble" + }, + { + "code": "RWF", + "name": "Rwanda franc" + }, + { + "code": "SHP", + "name": "Saint Helena pound" + }, + { + "code": "WST", + "name": "Samoan tala" + }, + { + "code": "SAR", + "name": "Saudi riyal" + }, + { + "code": "RSD", + "name": "Serbian dinar" + }, + { + "code": "SCR", + "name": "Seychelles rupee" + }, + { + "code": "SGD", + "name": "Singapore dollar" + }, + { + "code": "SKK", + "name": "Slovak koruna" + }, + { + "code": "SBD", + "name": "Solomon Islands dollar" + }, + { + "code": "KGS", + "name": "Som" + }, + { + "code": "TJS", + "name": "Somoni" + }, + { + "code": "ZAR", + "name": "South African rand" + }, + { + "code": "KRW", + "name": "South Korean won" + }, + { + "code": "ESP", + "name": "Spain Pesetas" + }, + { + "code": "LKR", + "name": "Sri Lanka rupee" + }, + { + "code": "SDG", + "name": "Sudanese pound" + }, + { + "code": "SRD", + "name": "Surinam dollar" + }, + { + "code": "SEK", + "name": "Swedish krona" + }, + { + "code": "CHF", + "name": "Swiss franc" + }, + { + "code": "SYP", + "name": "Syrian pound" + }, + { + "code": "TZS", + "name": "Tanzanian shilling" + }, + { + "code": "TTD", + "name": "Trinidad and Tobago dollar" + }, + { + "code": "MNT", + "name": "Tugrik" + }, + { + "code": "TND", + "name": "Tunisian dinar" + }, + { + "code": "TRL", + "name": "Turkey Liras" + }, + { + "code": "TRY", + "name": "Turkish Lira" + }, + { + "code": "UGX", + "name": "Uganda shilling" + }, + { + "code": "AED", + "name": "United Arab Emirates dirham" + }, + { + "code": "UYU", + "name": "Uruguayan Peso" + }, + { + "code": "USD", + "name": "US dollar" + }, + { + "code": "UZS", + "name": "Uzbekistan som" + }, + { + "code": "VUV", + "name": "Vatu" + }, + { + "code": "VEB", + "name": "Venezuela Bolivares" + }, + { + "code": "VEF", + "name": "Venezuelan bol\u00edvar fuerte" + }, + { + "code": "VND", + "name": "Vietnamese dong" + }, + { + "code": "YER", + "name": "Yemeni rial" + }, + { + "code": "PLN", + "name": "Zloty" + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/invoices.json b/tests/fixtures/invoices.json new file mode 100644 index 0000000..086f60d --- /dev/null +++ b/tests/fixtures/invoices.json @@ -0,0 +1,38 @@ +{ + "STATUS": "OK", + "invoices": [ + { + "project-name": "Colombia", + "exported-by-user-firstname": "", + "date-updated": "2025-01-11T14:54:08Z", + "time-cost": "0.00", + "total-cost": "0.00", + "project-id": "967489", + "date-created": "2025-01-11T14:54:08Z", + "status": "active", + "po-number": "", + "edited-by-user-firstname": "Php", + "description": "", + "edited-by-user-lastname": "Api", + "update-by-user-id": "391604", + "fixed-cost": "0.00", + "display-date": "20250101", + "id": "128550", + "due-date": "", + "company-name": "Php's Company", + "created-by-user-id": "391604", + "number": "10", + "pricing": "determine", + "exported-by-user-id": "", + "company-id": "1370007", + "exported-date": "", + "total-time-decimal": "0.00", + "created-by-user-firstname": "Php", + "exported-by-user-lastname": "", + "expenses-cost": "0.00", + "total-time": "0", + "created-by-user-lastname": "Api", + "currency-code": "USD" + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/invoices/128550.json b/tests/fixtures/invoices/128550.json new file mode 100644 index 0000000..34f3a00 --- /dev/null +++ b/tests/fixtures/invoices/128550.json @@ -0,0 +1,35 @@ +{ + "STATUS": "OK", + "invoice": { + "project-name": "Colombia", + "exported-by-user-firstname": "", + "date-updated": "2025-01-11T14:54:08Z", + "total-cost": "0.00", + "project-id": "967489", + "date-created": "2025-01-11T14:54:08Z", + "status": "active", + "po-number": "", + "edited-by-user-firstname": "Php", + "description": "", + "edited-by-user-lastname": "Api", + "update-by-user-id": "391604", + "fixed-cost": "", + "display-date": "20250101", + "id": "128550", + "due-date": "", + "company-name": "Php's Company", + "created-by-user-id": "391604", + "number": "10", + "pricing": "determine", + "exported-by-user-id": "", + "company-id": "1370007", + "exported-date": "", + "total-time-decimal": "0.00", + "created-by-user-firstname": "Php", + "exported-by-user-lastname": "", + "total-time": "0", + "line-items": [], + "created-by-user-lastname": "Api", + "currency-code": "USD" + } +} \ No newline at end of file diff --git a/tests/fixtures/projects/967489/invoices.json b/tests/fixtures/projects/967489/invoices.json new file mode 100644 index 0000000..086f60d --- /dev/null +++ b/tests/fixtures/projects/967489/invoices.json @@ -0,0 +1,38 @@ +{ + "STATUS": "OK", + "invoices": [ + { + "project-name": "Colombia", + "exported-by-user-firstname": "", + "date-updated": "2025-01-11T14:54:08Z", + "time-cost": "0.00", + "total-cost": "0.00", + "project-id": "967489", + "date-created": "2025-01-11T14:54:08Z", + "status": "active", + "po-number": "", + "edited-by-user-firstname": "Php", + "description": "", + "edited-by-user-lastname": "Api", + "update-by-user-id": "391604", + "fixed-cost": "0.00", + "display-date": "20250101", + "id": "128550", + "due-date": "", + "company-name": "Php's Company", + "created-by-user-id": "391604", + "number": "10", + "pricing": "determine", + "exported-by-user-id": "", + "company-id": "1370007", + "exported-date": "", + "total-time-decimal": "0.00", + "created-by-user-firstname": "Php", + "exported-by-user-lastname": "", + "expenses-cost": "0.00", + "total-time": "0", + "created-by-user-lastname": "Api", + "currency-code": "USD" + } + ] +} \ No newline at end of file