Activity API fixes + Payments API (#3076)

* Fixes for Store Payment Validation

* Tests for Payments

* Use custom validator to ensure payments are made ONLY to payable invoices

* Working on custom payment validators

* Update Client balance

* fixes for client balance

* Fixes for activity API
This commit is contained in:
David Bomba 2019-11-18 21:46:01 +11:00 committed by GitHub
parent 81c481c071
commit fe5a97e174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 413 additions and 163 deletions

View File

@ -29,9 +29,38 @@ class ActivityController extends BaseController
} }
/** /**
* Display a listing of the resource. * @OA\Get(
* path="/api/v1/actvities",
* operationId="getActivities",
* tags={"actvities"},
* summary="Gets a list of actvities",
* description="Lists all activities",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Response(
* response=200,
* description="A list of actvities",
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Activity"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* *
* @return \Illuminate\Http\Response
*/ */
public function index() public function index()
{ {

View File

@ -185,6 +185,40 @@ class PaymentController extends BaseController
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"), * @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"), * @OA\Parameter(ref="#/components/parameters/include"),
* @OA\RequestBody(
* description="The payment request",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="amount",
* description="The payment amount",
* type="number",
* format="float",
* ),
* @OA\Property(
* property="payment_date",
* example="2019/12/1",
* description="The payment date",
* type="string",
* ),
* @OA\Property(
* property="transation_reference",
* example="sdfasdfs98776d6kbkfd",
* description="The transaction reference for the payment",
* type="string",
* ),
* @OA\Property(
* property="invoices",
* example="j7s76d,s8765afk,D8fj3Sfdj",
* description="A comma separated list of invoice hashed ids that this payment relates to",
* type="string",
* )
* )
* )
* ),
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="Returns the saved Payment object", * description="Returns the saved Payment object",
@ -449,6 +483,7 @@ class PaymentController extends BaseController
public function destroy(DestroyPaymentRequest $request, Payment $payment) public function destroy(DestroyPaymentRequest $request, Payment $payment)
{ {
$payment->is_deleted = true;
$payment->delete(); $payment->delete();
return response()->json([], 200); return response()->json([], 200);

View File

@ -12,12 +12,14 @@
namespace App\Http\Requests\Payment; namespace App\Http\Requests\Payment;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidPayableInvoicesRule;
use App\Models\Payment; use App\Models\Payment;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
class StorePaymentRequest extends Request class StorePaymentRequest extends Request
{ {
use MakesHash; use MakesHash;
/** /**
* Determine if the user is authorized to make this request. * Determine if the user is authorized to make this request.
* *
@ -26,41 +28,47 @@ class StorePaymentRequest extends Request
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->can('create', Payment::class); return auth()->user()->can('create', Payment::class);
} }
public function rules() public function rules()
{ {
$this->sanitize(); $this->sanitize();
return [ $rules = [
'documents' => 'mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx', 'amount' => 'numeric|required',
'client_id' => 'integer|nullable',
'payment_type_id' => 'integer|nullable',
'amount' => 'numeric',
'payment_date' => 'required', 'payment_date' => 'required',
'client_id' => 'required',
'invoices' => 'required',
'invoices' => new ValidPayableInvoicesRule(),
]; ];
return $rules;
} }
public function sanitize() public function sanitize()
{ {
$input = $this->all(); $input = $this->all();
if(isset($input['invoices'])) if(isset($input['client_id']))
$input['invoices'] = $this->transformKeys(array_column($input['invoices']), 'id'); $input['client_id'] = $this->decodePrimaryKey($input['client_id']);
$this->replace($input); if(isset($input['invoices']))
$input['invoices'] = $this->transformKeys(explode(",", $input['invoices']));
if(is_array($input['invoices']) === false)
$input['invoices'] = null;
$this->replace($input);
return $this->all(); return $this->all();
}
public function messages()
{
} }
} }

View File

@ -0,0 +1,56 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Http\ValidationRules;
use App\Models\Invoice;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Validation\Rule;
/**
* Class ValidPayableInvoicesRule
* @package App\Http\ValidationRules
*/
class ValidPayableInvoicesRule implements Rule
{
use MakesHash;
/**
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value)
{
$invoices = Invoice::whereIn('id', $this->transformKeys(explode(",",$value)))->get();
if(!$invoices || $invoices->count() == 0)
return false;
foreach ($invoices as $invoice) {
if(! $invoice->isPayable())
return false;
}
return true;
}
/**
* @return string
*/
public function message()
{
return "One or more of these invoices have been paid";
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Client;
use App\Models\Client;
use Illuminate\Foundation\Bus\Dispatchable;
class UpdateClientBalance
{
use Dispatchable;
protected $amount;
protected $client;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Client $client, $amount)
{
$this->amount = $amount;
$this->client = $client;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->client->balance += $this->amount;
$this->client->paid_to_date += $this->amount;
$this->client->save();
}
}

View File

@ -11,6 +11,7 @@
namespace App\Jobs\Invoice; namespace App\Jobs\Invoice;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice; use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment; use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Util\SystemLogger; use App\Jobs\Util\SystemLogger;
@ -51,7 +52,7 @@ class UpdateInvoicePayment implements ShouldQueue
$invoices_total = $invoices->sum('balance'); $invoices_total = $invoices->sum('balance');
/* Simplest scenario*/ /* Simplest scenario - All invoices are paid in full*/
if(strval($invoices_total) === strval($this->payment->amount)) if(strval($invoices_total) === strval($this->payment->amount))
{ {
$invoices->each(function ($invoice){ $invoices->each(function ($invoice){
@ -59,15 +60,18 @@ class UpdateInvoicePayment implements ShouldQueue
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1)); UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1));
$invoice->clearPartial(); $invoice->clearPartial();
$invoice->updateBalance($invoice->balance*-1); $invoice->updateBalance($invoice->balance*-1);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->balance*-1);
}); });
} }
/*Combination of partials and full invoices are being paid*/
else { else {
$total = 0; $total = 0;
/* Calculate the grand total of the invoices*/
foreach($invoices as $invoice) foreach($invoices as $invoice)
{ {
@ -78,7 +82,7 @@ class UpdateInvoicePayment implements ShouldQueue
} }
/* test if there is a batch of partial invoices that have been paid */ /*Test if there is a batch of partial invoices that have been paid */
if($this->payment->amount == $total) if($this->payment->amount == $total)
{ {
@ -91,6 +95,8 @@ class UpdateInvoicePayment implements ShouldQueue
$invoice->clearPartial(); $invoice->clearPartial();
$invoice->setDueDate(); $invoice->setDueDate();
$invoice->setStatus(Invoice::STATUS_PARTIAL); $invoice->setStatus(Invoice::STATUS_PARTIAL);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->partial*-1);
} }
else else
@ -98,6 +104,9 @@ class UpdateInvoicePayment implements ShouldQueue
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1)); UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1));
$invoice->clearPartial(); $invoice->clearPartial();
$invoice->updateBalance($invoice->balance*-1); $invoice->updateBalance($invoice->balance*-1);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->balance*-1);
} }
}); });

View File

@ -120,18 +120,18 @@ class Activity extends StaticModel
return $this->belongsTo(Payment::class)->withTrashed(); return $this->belongsTo(Payment::class)->withTrashed();
} }
public function task() // public function task()
{ // {
return $this->belongsTo(Task::class)->withTrashed(); // return $this->belongsTo(Task::class)->withTrashed();
} // }
public function expense() // public function expense()
{ // {
return $this->belongsTo(Expense::class)->withTrashed(); // return $this->belongsTo(Expense::class)->withTrashed();
} // }
public function company() public function company()
{ {
return $this->belongsTo(Company::class)->withTrashed(); return $this->belongsTo(Company::class);
} }
} }

View File

@ -22,7 +22,7 @@ class GatewayType extends StaticModel
const CREDIT_CARD = 1; const CREDIT_CARD = 1;
const BANK_TRANSFER = 2; const BANK_TRANSFER = 2;
const PAYPAL = 3; const PAYPAL = 3;
const BITCOIN = 4; const CRYPTO = 4;
const DWOLLA = 5; const DWOLLA = 5;
const CUSTOM1 = 6; const CUSTOM1 = 6;
const ALIPAY = 7; const ALIPAY = 7;

View File

@ -18,13 +18,15 @@ use App\Utils\Number;
use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Payment extends BaseModel class Payment extends BaseModel
{ {
use MakesHash; use MakesHash;
use Filterable; use Filterable;
use MakesDates; use MakesDates;
use SoftDeletes;
const STATUS_PENDING = 1; const STATUS_PENDING = 1;
const STATUS_VOIDED = 2; const STATUS_VOIDED = 2;
const STATUS_FAILED = 3; const STATUS_FAILED = 3;
@ -147,6 +149,7 @@ class Payment extends BaseModel
public function resolveRouteBinding($value) public function resolveRouteBinding($value)
{ {
return $this return $this
->withTrashed()
->where('id', $this->decodePrimaryKey($value))->firstOrFail(); ->where('id', $this->decodePrimaryKey($value))->firstOrFail();
} }
} }

View File

@ -11,6 +11,10 @@
namespace App\Repositories; namespace App\Repositories;
use App\Events\Payment\PaymentWasCreated;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Invoice\UpdateInvoicePayment;
use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -20,7 +24,6 @@ use Illuminate\Http\Request;
class PaymentRepository extends BaseRepository class PaymentRepository extends BaseRepository
{ {
public function getClassName() public function getClassName()
{ {
return Payment::class; return Payment::class;
@ -30,20 +33,24 @@ class PaymentRepository extends BaseRepository
{ {
$payment->fill($request->input()); $payment->fill($request->input());
$payment->save();
if($request->input('invoices')) if($request->input('invoices'))
{ {
$invoices = Invoice::whereIn('id', $request->input('invoices'))->get(); $invoices = Invoice::whereIn('id', $request->input('invoices'))->get();
$payment->invoices()->saveMany($invoices);
} }
//parse invoices[] and attach to paymentables event(new PaymentWasCreated($payment));
//parse invoices[] and apply payments and subfunctions
UpdateInvoicePayment::dispatchNow($payment);
$payment->save();
return $payment; return $payment;
} }
} }

View File

@ -27,17 +27,17 @@ class ActivityTransformer extends EntityTransformer
return [ return [
'id' => (string) $this->encodePrimaryKey($activity->id), 'id' => (string) $this->encodePrimaryKey($activity->id),
'activity_type_id' => (string) $activity->activity_type_id, 'activity_type_id' => (string) $activity->activity_type_id,
'client_id' => $activity->client ? (string) $activity->client->id : '', 'client_id' => $activity->client ? (string) $this->encodePrimaryKey($activity->client->id) : '',
'company_id' => $activity->company ? (string) $activity->company->id : '', 'company_id' => $activity->company ? (string) $this->encodePrimaryKey($activity->company->id) : '',
'user_id' => (string) $activity->user_id, 'user_id' => (string) $activity->user_id,
'invoice_id' => $activity->invoice ? (string) $activity->invoice->id : '', 'invoice_id' => $activity->invoice ? (string) $this->encodePrimaryKey($activity->invoice->id) : '',
'payment_id' => $activity->payment ? (string) $activity->payment->id : '', 'payment_id' => $activity->payment ? (string) $this->encodePrimaryKey($activity->payment->id) : '',
'credit_id' => $activity->credit ? (string) $activity->credit->id : '', 'credit_id' => $activity->credit ? (string) $this->encodePrimaryKey($activity->credit->id) : '',
'updated_at' => $activity->updated_at, 'updated_at' => $activity->updated_at,
'expense_id' => $activity->expense_id ? (string) $activity->expense->id : '', 'expense_id' => $activity->expense_id ? (string) $this->encodePrimaryKey($activity->expense->id) : '',
'is_system' => (bool) $activity->is_system, 'is_system' => (bool) $activity->is_system,
'contact_id' => $activity->contact_id ? (string) $activity->contact->id : '', 'contact_id' => $activity->contact_id ? (string) $this->encodePrimaryKey($activity->contact->id) : '',
'task_id' => $activity->task_id ? (string) $activity->task->id : '', 'task_id' => $activity->task_id ? (string) $this->encodePrimaryKey($activity->task->id) : '',
'notes' => $activity->notes ? (string) $activity->notes : '', 'notes' => $activity->notes ? (string) $activity->notes : '',
'ip' => (string) $activity->ip, 'ip' => (string) $activity->ip,

View File

@ -27,7 +27,7 @@ class PaymentTransformer extends EntityTransformer
protected $availableIncludes = [ protected $availableIncludes = [
'client', 'client',
'invoice', 'invoices',
]; ];
public function __construct($serializer = null) public function __construct($serializer = null)
@ -37,11 +37,11 @@ class PaymentTransformer extends EntityTransformer
} }
public function includeInvoice(Payment $payment) public function includeInvoices(Payment $payment)
{ {
$transformer = new InvoiceTransformer($this->serializer); $transformer = new InvoiceTransformer($this->serializer);
return $this->includeItem($payment->invoice, $transformer, Invoice::class); return $this->includeCollection($payment->invoices, $transformer, Invoice::class);
} }
public function includeClient(Payment $payment) public function includeClient(Payment $payment)
@ -65,6 +65,7 @@ class PaymentTransformer extends EntityTransformer
'is_deleted' => (bool) $payment->is_deleted, 'is_deleted' => (bool) $payment->is_deleted,
'payment_type_id' => (string) $payment->payment_type_id ?: '', 'payment_type_id' => (string) $payment->payment_type_id ?: '',
'invitation_id' => (string) $payment->invitation_id ?: '', 'invitation_id' => (string) $payment->invitation_id ?: '',
'client_id' => (string) $this->encodePrimaryKey($payment->client_id),
/* /*
'private_notes' => $payment->private_notes ?: '', 'private_notes' => $payment->private_notes ?: '',
'exchange_rate' => (float) $payment->exchange_rate, 'exchange_rate' => (float) $payment->exchange_rate,

View File

@ -6,6 +6,7 @@ use App\Models\Payment;
use Faker\Generator as Faker; use Faker\Generator as Faker;
$factory->define(App\Models\Payment::class, function (Faker $faker) { $factory->define(App\Models\Payment::class, function (Faker $faker) {
return [ return [
'is_deleted' => false, 'is_deleted' => false,
'amount' => $faker->numberBetween(1,10), 'amount' => $faker->numberBetween(1,10),
@ -14,6 +15,7 @@ $factory->define(App\Models\Payment::class, function (Faker $faker) {
'payment_type_id' => Payment::TYPE_CREDIT_CARD, 'payment_type_id' => Payment::TYPE_CREDIT_CARD,
'status_id' => Payment::STATUS_COMPLETED 'status_id' => Payment::STATUS_COMPLETED
]; ];
}); });

View File

@ -4,8 +4,13 @@ namespace Tests\Feature;
use App\DataMapper\ClientSettings; use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use App\Factory\ClientFactory;
use App\Factory\InvoiceFactory;
use App\Factory\PaymentFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Models\Account; use App\Models\Account;
use App\Models\Client; use App\Models\Client;
use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -15,6 +20,8 @@ use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Tests\MockAccountData;
use Tests\TestCase; use Tests\TestCase;
/** /**
@ -27,7 +34,7 @@ class PaymentTest extends TestCase
use MakesHash; use MakesHash;
use DatabaseTransactions; use DatabaseTransactions;
use MockAccountData;
public function setUp() :void public function setUp() :void
{ {
@ -39,67 +46,40 @@ class PaymentTest extends TestCase
Model::reguard(); Model::reguard();
$this->makeTestData();
$this->withoutExceptionHandling();
} }
public function testPaymentList() public function testPaymentList()
{ {
$data = [
'first_name' => $this->faker->firstName,
'last_name' => $this->faker->lastName,
'name' => $this->faker->company,
'email' => $this->faker->unique()->safeEmail,
'password' => 'ALongAndBrilliantPassword123',
'_token' => csrf_token(),
'privacy_policy' => 1,
'terms_of_service' => 1
];
$response = $this->withHeaders([ factory(\App\Models\Client::class, 1)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) {
'X-API-SECRET' => config('ninja.api_secret'),
])->post('/api/v1/signup?include=account', $data);
$acc = $response->json();
$account = Account::find($this->decodePrimaryKey($acc['data'][0]['account']['id']));
$company_token = $account->default_company->tokens()->first();
$token = $company_token->token;
$company = $company_token->company;
$user = $company_token->user;
$this->assertNotNull($company_token);
$this->assertNotNull($token);
$this->assertNotNull($user);
$this->assertNotNull($company);
//$this->assertNotNull($user->token->company);
factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
factory(\App\Models\ClientContact::class,1)->create([ factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id, 'user_id' => $this->user->id,
'client_id' => $c->id, 'client_id' => $c->id,
'company_id' => $company->id, 'company_id' => $this->company->id,
'is_primary' => 1 'is_primary' => 1
]); ]);
factory(\App\Models\ClientContact::class,1)->create([ factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id, 'user_id' => $this->user->id,
'client_id' => $c->id, 'client_id' => $c->id,
'company_id' => $company->id 'company_id' => $this->company->id
]); ]);
}); });
$client = Client::all()->first(); $client = Client::all()->first();
factory(\App\Models\Payment::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); factory(\App\Models\Payment::class, 1)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $client->id]);
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $token, 'X-API-TOKEN' => $this->token,
])->get('/api/v1/payments'); ])->get('/api/v1/payments');
$response->assertStatus(200); $response->assertStatus(200);
@ -108,95 +88,164 @@ class PaymentTest extends TestCase
public function testPaymentRESTEndPoints() public function testPaymentRESTEndPoints()
{ {
$data = [
'first_name' => $this->faker->firstName,
'last_name' => $this->faker->lastName,
'name' => $this->faker->company,
'email' => $this->faker->unique()->safeEmail,
'password' => 'ALongAndBrilliantPassword123',
'_token' => csrf_token(),
'privacy_policy' => 1,
'terms_of_service' => 1
];
factory(\App\Models\Payment::class, 1)->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
$Payment = Payment::all()->last();
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
])->post('/api/v1/signup?include=account', $data); 'X-API-TOKEN' => $this->token,
$acc = $response->json();
$account = Account::find($this->decodePrimaryKey($acc['data'][0]['account']['id']));
$company_token = $account->default_company->tokens()->first();
$token = $company_token->token;
$company = $company_token->company;
$user = $company_token->user;
$this->assertNotNull($company_token);
$this->assertNotNull($token);
$this->assertNotNull($user);
$this->assertNotNull($company);
//$this->assertNotNull($user->token->company);
factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id,
'is_primary' => 1
]);
factory(\App\Models\ClientContact::class,1)->create([
'user_id' => $user->id,
'client_id' => $c->id,
'company_id' => $company->id
]);
});
$client = Client::all()->first();
factory(\App\Models\Payment::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
$Payment = Payment::all()->first();
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $token,
])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id)); ])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id));
$response->assertStatus(200); $response->assertStatus(200);
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $token, 'X-API-TOKEN' => $this->token,
])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id).'/edit'); ])->get('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id).'/edit');
$response->assertStatus(200); $response->assertStatus(200);
$Payment_update = [ }
'amount' => 10,
'payment_date' => Carbon::now() public function testStorePaymentWithoutClientId()
]; {
$client = ClientFactory::create($this->company->id, $this->user->id);
$this->assertNotNull($Payment); $client->save();
$this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id
$response = $this->withHeaders([ $this->invoice->client_id = $client->id;
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $token, $this->invoice->line_items = $this->buildLineItems();
])->put('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id), $Payment_update) $this->invoice->uses_inclusive_Taxes = false;
->assertStatus(200);
$this->invoice->save();
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), $this->invoice_calc = new InvoiceSum($this->invoice);
'X-API-TOKEN' => $token, $this->invoice_calc->build();
])->delete('/api/v1/payments/'.$this->encodePrimaryKey($Payment->id));
$this->invoice = $this->invoice_calc->getInvoice();
$response->assertStatus(200);
$data = [
'amount' => $this->invoice->amount,
'invoices' => $this->invoice->hashed_id,
'payment_date' => '2020/12/11',
];
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/', $data);
}
catch(ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(),1);
$this->assertTrue(array_key_exists('client_id', $message));
}
}
public function testStorePaymentWithClientId()
{
$client = ClientFactory::create($this->company->id, $this->user->id);
$client->save();
$this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id
$this->invoice->client_id = $client->id;
$this->invoice->status_id = Invoice::STATUS_SENT;
$this->invoice->line_items = $this->buildLineItems();
$this->invoice->uses_inclusive_Taxes = false;
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice->save();
$data = [
'amount' => $this->invoice->amount,
'client_id' => $client->hashed_id,
'invoices' => $this->invoice->hashed_id,
'payment_date' => '2020/12/12',
];
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments?include=invoices', $data);
}
catch(ValidationException $e) {
\Log::error('in the validator');
$message = json_decode($e->validator->getMessageBag(),1);
\Log::error($message);
$this->assertNotNull($message);
}
$arr = $response->json();
\Log::error($arr);
$response->assertStatus(200);
}
public function testStorePaymentWithNoInvoiecs()
{
$client = ClientFactory::create($this->company->id, $this->user->id);
$client->save();
$this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id
$this->invoice->client_id = $client->id;
$this->invoice->status_id = Invoice::STATUS_SENT;
$this->invoice->line_items = $this->buildLineItems();
$this->invoice->uses_inclusive_Taxes = false;
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice->save();
$data = [
'amount' => $this->invoice->amount,
'client_id' => $client->hashed_id,
'invoices' => '',
'payment_date' => '2020/12/12',
];
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments?include=invoices', $data);
}
catch(ValidationException $e) {
\Log::error('in the validator');
$message = json_decode($e->validator->getMessageBag(),1);
\Log::error($message);
$this->assertNotNull($message);
}
} }
} }