Browse Source

Create project invoice feature wip

pull/1/head
Nafies Luthfi 8 years ago
parent
commit
77dcbb6b36
  1. 17
      app/Entities/Invoices/Invoice.php
  2. 133
      app/Http/Controllers/InvoiceDraftController.php
  3. 14
      app/Http/Controllers/InvoicesController.php
  4. 113
      app/Services/InvoiceDraft/InvoiceDraft.php
  5. 150
      app/Services/InvoiceDraft/InvoiceDraftCollection.php
  6. 30
      app/Services/InvoiceDraft/Item.php
  7. 38
      database/migrations/2017_10_05_162758_create_invoices_table.php
  8. 31
      resources/lang/id/invoice.php
  9. 26
      resources/views/invoices/create.blade.php
  10. 59
      resources/views/invoices/partials/draft-confirm.blade.php
  11. 62
      resources/views/invoices/partials/draft-item-list.blade.php
  12. 6
      resources/views/invoices/partials/form-draft-detail.blade.php
  13. 17
      resources/views/invoices/partials/invoice-draft-tabs.blade.php
  14. 1
      routes/web.php
  15. 23
      routes/web/invoices.php
  16. 169
      tests/Feature/InvoiceEntryTest.php
  17. 152
      tests/Unit/InvoiceDraftCollectionTest.php

17
app/Entities/Invoices/Invoice.php

@ -0,0 +1,17 @@
<?php
namespace App\Entities\Invoices;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
protected $guarded = ['id','created_at','updated_at'];
protected $casts = ['items' => 'array'];
public function getRouteKeyName()
{
return 'invoice_no';
}
}

133
app/Http/Controllers/InvoiceDraftController.php

@ -0,0 +1,133 @@
<?php
namespace App\Http\Controllers;
use App\Entities\Projects\Project;
use App\Services\InvoiceDrafts\InvoiceDraft;
use App\Services\InvoiceDrafts\InvoiceDraftCollection;
use App\Services\InvoiceDrafts\Item;
use Illuminate\Http\Request;
class InvoiceDraftController extends Controller
{
private $draftCollection;
public function __construct()
{
$this->draftCollection = new InvoiceDraftCollection();
}
public function index(Request $request)
{
$draft = $this->draftCollection->content()->first();
$projects = Project::pluck('name', 'id');
return view('invoices.create', compact('draft', 'projects'));
}
public function show(Request $request, $draftKey = null)
{
$draft = $draftKey ? $this->draftCollection->get($draftKey) : $this->draftCollection->content()->first();
if (is_null($draft)) {
flash(trans('invoice.draft_not_found'), 'danger');
return redirect()->route('invoices.create');
}
$projects = Project::pluck('name', 'id');
return view('invoices.create', compact('draft', 'projects'));
}
public function add(Request $request)
{
$this->draftCollection->add(new InvoiceDraft());
return redirect()->route('invoices.create', $this->draftCollection->content()->last()->draftKey);
}
public function addDraftItem(Request $request, $draftKey)
{
$item = new Item(['description' => $request->description, 'amount' => $request->amount]);
$this->draftCollection->addItemToDraft($draftKey, $item);
flash(trans('invoice.item_added'));
return back();
}
public function updateDraftItem(Request $request, $draftKey)
{
$this->draftCollection->updateDraftItem($draftKey, $request->item_key, $request->only('description', 'amount'));
return back();
}
public function removeDraftItem(Request $request, $draftKey)
{
$this->draftCollection->removeItemFromDraft($draftKey, $request->item_index);
return back();
}
public function empty($draftKey)
{
$this->draftCollection->emptyDraft($draftKey);
return redirect()->route('invoices.create', $draftKey);
}
public function remove(Request $request)
{
$this->draftCollection->removeDraft($request->draft_key);
if ($this->draftCollection->isEmpty()) {
return redirect()->route('invoices.create-empty');
}
$lastDraft = $this->draftCollection->content()->last();
return redirect()->route('invoices.create', $lastDraft->draftKey);
}
public function destroy()
{
$this->draftCollection->destroy();
flash(trans('invoice.draft_destroyed'), 'warning');
return redirect()->route('cart.index');
}
public function proccess(Request $request, $draftKey)
{
$this->validate($request, [
'project_id' => 'required|exists:projects,id',
'notes' => 'nullable|string|max:100',
]);
$draft = $this->draftCollection->updateDraftAttributes($draftKey, $request->only('project_id', 'notes'));
if ($draft->getItemsCount() == 0) {
flash(trans('invoice.item_list_empty'), 'warning')->important();
return redirect()->route('invoices.create', [$draftKey]);
}
flash(trans('invoice.confirm_instruction', ['back_link' => link_to_route('invoices.create', trans('app.back'), $draftKey)]), 'warning')->important();
return redirect()->route('invoices.create', [$draftKey, 'action' => 'confirm']);
}
public function store(Request $request, $draftKey)
{
$draft = $this->draftCollection->get($draftKey);
if (is_null($draft)) {
return redirect()->route('cart.index');
}
$invoice = $draft->store();
$draft->destroy();
flash(trans('invoice.created', ['invoice_no' => $invoice->invoice_no]), 'success')->important();
return redirect()->route('invoices.show', $invoice->invoice_no);
}
}

14
app/Http/Controllers/InvoicesController.php

@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers;
use App\Entities\Invoices\Invoice;
use Illuminate\Http\Request;
class InvoicesController extends Controller
{
public function show(Invoice $invoice)
{
return $invoice;
}
}

113
app/Services/InvoiceDraft/InvoiceDraft.php

@ -0,0 +1,113 @@
<?php
namespace App\Services\InvoiceDrafts;
use App\Entities\Invoices\Invoice;
/**
* Invoice Draft.
*/
class InvoiceDraft
{
public $items = [];
public $projectId;
public $notes;
public function items()
{
return collect($this->items)->sortBy('name');
}
public function addItem(Item $item)
{
$this->items[] = $item;
return $item;
}
public function removeItem($itemKey)
{
unset($this->items[$itemKey]);
}
public function empty()
{
$this->items = [];
}
public function getTotal()
{
return $this->items()->sum('amount');
}
public function getItemsCount()
{
return $this->items()->count();
}
public function updateItem($itemKey, $newItemData)
{
if (!isset($this->items[$itemKey])) {
return;
}
$item = $this->items[$itemKey];
$this->items[$itemKey] = $item->updateAttribute($newItemData);
return $item;
}
public function store()
{
$invoice = new Invoice();
$invoice->invoice_no = $this->getNewInvoiceNo();
$invoice->items = $this->getItemsArray();
$invoice->project_id = $this->projectId;
$invoice->amount = $this->getTotal();
$invoice->notes = $this->notes;
$invoice->status_id = 1;
$invoice->user_id = auth()->id() ?: 1;
$invoice->save();
return $invoice;
}
public function getNewInvoiceNo()
{
$prefix = date('ym');
$lastInvoice = Invoice::orderBy('invoice_no', 'desc')->first();
if (!is_null($lastInvoice)) {
$lastInvoiceNo = $lastInvoice->invoice_no;
if (substr($lastInvoiceNo, 0, 4) == $prefix) {
return ++$lastInvoiceNo;
}
}
return $prefix.'0001';
}
protected function getItemsArray()
{
$items = [];
foreach ($this->items as $item) {
$items[] = [
'description' => $item->description,
'amount' => $item->amount,
];
}
return $items;
}
public function destroy()
{
$cart = app(InvoiceDraftCollection::class);
return $cart->removeDraft($this->draftKey);
}
}

150
app/Services/InvoiceDraft/InvoiceDraftCollection.php

@ -0,0 +1,150 @@
<?php
namespace App\Services\InvoiceDrafts;
use App\Product;
use Illuminate\Support\Collection;
/**
* InvoiceDraft Collection Class.
*/
class InvoiceDraftCollection
{
private $instance;
private $session;
public function __construct()
{
$this->session = session();
$this->instance('drafts');
}
public function instance($instance = null)
{
$instance = $instance ?: 'drafts';
$this->instance = sprintf('%s.%s', 'invoices', $instance);
return $this;
}
public function currentInstance()
{
return str_replace('invoices.', '', $this->instance);
}
public function add(InvoiceDraft $draft)
{
$content = $this->getContent();
$draft->draftKey = str_random(10);
$content->put($draft->draftKey, $draft);
$this->session->put($this->instance, $content);
return $draft;
}
public function get($draftKey)
{
$content = $this->getContent();
if (isset($content[$draftKey])) {
return $content[$draftKey];
}
}
public function updateDraftAttributes($draftKey, $draftAttributes)
{
$content = $this->getContent();
$content[$draftKey]->projectId = $draftAttributes['project_id'];
$content[$draftKey]->notes = $draftAttributes['notes'];
$this->session->put($this->instance, $content);
return $content[$draftKey];
}
public function emptyDraft($draftKey)
{
$content = $this->getContent();
$content[$draftKey]->empty();
$this->session->put($this->instance, $content);
}
public function removeDraft($draftKey)
{
$content = $this->getContent();
$content->pull($draftKey);
$this->session->put($this->instance, $content);
}
public function content()
{
return $this->getContent();
}
protected function getContent()
{
$content = $this->session->has($this->instance) ? $this->session->get($this->instance) : collect([]);
return $content;
}
public function keys()
{
return $this->getContent()->keys();
}
public function destroy()
{
$this->session->remove($this->instance);
}
public function addItemToDraft($draftKey, Item $item)
{
$content = $this->getContent();
$content[$draftKey]->addItem($item);
$this->session->put($this->instance, $content);
return $item;
}
public function draftHasItem(TrasactionDraft $draft, Product $product)
{
$item = $draft->search($product);
return !is_null($item);
}
public function updateDraftItem($draftKey, $itemKey, $newItemData)
{
$content = $this->getContent();
$content[$draftKey]->updateItem($itemKey, $newItemData);
$this->session->put($this->instance, $content);
}
public function removeItemFromDraft($draftKey, $itemKey)
{
$content = $this->getContent();
$content[$draftKey]->removeItem($itemKey);
$this->session->put($this->instance, $content);
}
public function count()
{
return $this->getContent()->count();
}
public function isEmpty()
{
return $this->count() == 0;
}
public function hasContent()
{
return !$this->isEmpty();
}
}

30
app/Services/InvoiceDraft/Item.php

@ -0,0 +1,30 @@
<?php
namespace App\Services\InvoiceDrafts;
/**
* Draft Item class.
*/
class Item
{
public $description;
public $amount;
public function __construct(array $itemDetail)
{
$this->description = $itemDetail['description'];
$this->amount = $itemDetail['amount'];
}
public function updateAttribute(array $newItemData)
{
if (isset($newItemData['description'])) {
$this->description = $newItemData['description'];
}
if (isset($newItemData['amount'])) {
$this->amount = $newItemData['amount'];
}
return $this;
}
}

38
database/migrations/2017_10_05_162758_create_invoices_table.php

@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateInvoicesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('invoices', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('project_id');
$table->string('invoice_no', 8);
$table->text('items');
$table->unsignedInteger('amount');
$table->string('notes');
$table->unsignedTinyInteger('status_id');
$table->unsignedInteger('user_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('invoices');
}
}

31
resources/lang/id/invoice.php

@ -0,0 +1,31 @@
<?php
return [
// Labels
'invoice' => 'Invoice',
'list' => 'Daftar Invoice',
'search' => 'Cari Invoice',
'detail' => 'Detail Invoice',
'not_found' => 'Invoice tidak ditemukan',
'empty' => 'Belum ada Invoice',
'back_to_index' => 'Kembali ke daftar Invoice',
// Actions
'proccess' => 'Proses Invoice',
'create' => 'Input Invoice Baru',
'created' => 'Input Invoice baru telah berhasil.',
'show' => 'Detail Invoice',
'edit' => 'Edit Invoice',
'update' => 'Update Invoice',
'updated' => 'Update data Invoice telah berhasil.',
'delete' => 'Hapus Invoice',
'delete_confirm' => 'Anda yakin akan menghapus Invoice ini?',
'deleted' => 'Hapus data Invoice telah berhasil.',
'undeleted' => 'Data Invoice gagal dihapus.',
'undeleteable' => 'Data Invoice tidak dapat dihapus.',
// Attributes
'project' => 'Project',
'items' => 'Item Invoice',
'notes' => 'Catatan',
];

26
resources/views/invoices/create.blade.php

@ -0,0 +1,26 @@
@extends('layouts.app')
@section('title', 'Entry Invoice')
@section('content')
<div class="pull-right">
<form action="{{ route('invoices.add') }}" method="POST">
{{ csrf_field() }}
<input type="submit" class="btn btn-default navbar-btn" name="create-invoice-draft" id="invoice-draft-create-button" value="{{ trans('invoice.create') }}">
</form>
</div>
<h1 class="page-header">{{ trans('invoice.list') }}</h1>
<?php use Facades\App\Services\InvoiceDrafts\InvoiceDraftCollection; ?>
@includeWhen(! InvoiceDraftCollection::isEmpty(), 'invoices.partials.invoice-draft-tabs')
@if ($draft)
@if (Request::get('action') == 'confirm')
@include('invoices.partials.draft-confirm')
@else
<div class="row">
<div class="col-md-9">@include('invoices.partials.draft-item-list')</div>
<div class="col-md-3">@include('invoices.partials.form-draft-detail')</div>
</div>
@endif
@endif
@endsection

59
resources/views/invoices/partials/draft-confirm.blade.php

@ -0,0 +1,59 @@
<div class="row">
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('invoice.confirm') }}</h3></div>
<div class="panel-body">
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Deskripsi</th>
<th class="text-right">Biaya</th>
</tr>
</thead>
<tbody>
@forelse($draft->items() as $key => $item)
<tr>
<td>{{ $key + 1 }}</td>
<td>{{ $item->description }}</td>
<td class="text-right">{{ formatRp($item->amount) }}</td>
</tr>
@empty
@endforelse
</tbody>
<tfoot>
<tr>
<th colspan="5" class="text-right">{{ trans('invoice.total') }} :</th>
<th class="text-right">{{ formatRp($draft->getTotal()) }}</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('invoice.detail') }}</h3></div>
<div class="panel-body">
<table class="table table-condensed">
<tbody>
<tr>
<td>{{ trans('invoice.project') }}</td>
<td>
{{ App\Entities\Projects\Project::findOrFail($draft->projectId)->name }}
</td>
</tr>
<tr><td>{{ trans('invoice.total') }}</td><th class="text-right">{{ formatRp($draft->getTotal()) }}</th></tr>
<tr><td>{{ trans('invoice.notes') }}</td><td>{{ $draft->notes }}</td></tr>
</tbody>
</table>
</div>
<div class="panel-footer">
{{ Form::open(['route' => ['invoices.store', $draft->draftKey]]) }}
{{ Form::submit(trans('invoice.save'), ['id' => 'save-invoice-draft', 'class' => 'btn btn-success']) }}
{{ link_to_route('invoices.create', trans('app.back'), $draft->draftKey, ['class' => 'btn btn-default']) }}
{{ Form::close() }}
</div>
</div>
</div>
</div>

62
resources/views/invoices/partials/draft-item-list.blade.php

@ -0,0 +1,62 @@
<legend>
{{ trans('invoice.items') }}
<small class="text-muted">
({{ $draft->getItemsCount() }} Item)
</small>
</legend>
<div class="panel panel-default">
<div class="panel-body table-responsive">
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Deskripsi</th>
<th>Biaya</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
<?php $no = 1 ?>
@forelse($draft->items() as $key => $item)
<tr>
<td>{{ $no }} <?php $no++ ?></td>
{{ Form::open(['route' => ['cart.update-draft-item', $draft->draftKey], 'method' => 'patch']) }}
{{ Form::hidden('item_key', $key) }}
<td>{{ Form::text('description', $item->description, ['id' => 'description-' . $key]) }}</td>
<td>
{{ Form::number('amount', $item->amount, ['id' => 'amount-' . $key]) }}
</td>
{{ Form::submit('update-item-' . $key, ['style'=>'display:none']) }}
{{ Form::close() }}
<td class="text-center show-on-hover-parent">
{!! FormField::delete([
'route' => ['cart.remove-draft-item', $draft->draftKey],
'onsubmit' => 'Yakin ingin menghapus Item ini?',
'class' => '',
], 'x', ['id' => 'remove-item-' . $key, 'class' => 'btn btn-danger btn-xs show-on-hover','title' => 'Hapus item ini'], ['item_index' => $key]) !!}
</td>
</tr>
@empty
@endforelse
<tr>
<td></td>
{{ Form::open(['route' => ['cart.add-draft-item', $draft->draftKey]]) }}
<td>{{ Form::text('description', null, ['id' => 'description']) }}</td>
<td>
{{ Form::number('amount', null, ['id' => 'amount']) }}
</td>
<td class="text-center">{{ Form::submit('add-item', ['class' => 'btn btn-primary']) }}</td>
{{ Form::close() }}
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-right">{{ trans('invoice.amount') }} :</th>
<th class="text-right">{{ formatRp($draft->getTotal()) }}</th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</div>

6
resources/views/invoices/partials/form-draft-detail.blade.php

@ -0,0 +1,6 @@
<legend>{{ trans('invoice.detail') }}</legend>
{{ Form::open(['route' => ['cart.draft-proccess', $draft->draftKey], 'method' => 'patch']) }}
{!! FormField::select('project_id', $projects, ['label' => trans('invoice.project'), 'required' => true]) !!}
{!! FormField::textarea('notes', ['label' => trans('invoice.notes'), 'value' => $draft->notes]) !!}
{{ Form::submit(trans('invoice.proccess'), ['class' => 'btn btn-info']) }}
{{ Form::close() }}

17
resources/views/invoices/partials/invoice-draft-tabs.blade.php

@ -0,0 +1,17 @@
<?php use Facades\App\Services\InvoiceDrafts\InvoiceDraftCollection; ?>
<ul class="nav nav-tabs transaction-draft-tabs">
@foreach(InvoiceDraftCollection::content() as $key => $content)
<?php $active = ($draft->draftKey == $key) ? 'class=active' : '' ?>
<li {{ $active }} role="presentation">
<a href="{{ route('invoices.create', $key) }}">
{{ trans('invoice.invoice') }} - {{ $key }}
<form action="{{ route('cart.remove') }}" method="post" style="display:inline" onsubmit="return confirm('Yakin ingin menghapus Draft Transaksi ini?')">
{{ csrf_field() }}
{{ method_field('delete') }}
<input type="hidden" name="draft_key" value="{{ $key }}">
<input type="submit" value="x" style="margin: -2px -7px 0px 0px" class="btn-link btn-xs pull-right">
</form>
</a>
</li>
@endforeach
</ul><!-- Tab panes -->

1
routes/web.php

@ -11,5 +11,6 @@ require __DIR__ . '/web/projects.php';
require __DIR__ . '/web/payments.php';
require __DIR__ . '/web/subscriptions.php';
require __DIR__ . '/web/reports.php';
require __DIR__ . '/web/invoices.php';
require __DIR__ . '/web/options-vue.php';
require __DIR__ . '/web/calendar.php';

23
routes/web/invoices.php

@ -0,0 +1,23 @@
<?php
Route::group(['middleware' => ['web','role:admin']], function() {
/*
* Invoice Draft Routes
*/
Route::get('invoices/create', 'InvoiceDraftController@index')->name('invoices.create-empty');
Route::get('invoices/create/{draftKey?}', 'InvoiceDraftController@show')->name('invoices.create');
Route::post('invoices/create/{draftKey}', 'InvoiceDraftController@store')->name('invoices.store');
Route::post('invoices/add-draft', 'InvoiceDraftController@add')->name('invoices.add');
Route::post('cart/add-draft-item/{draftKey}', 'InvoiceDraftController@addDraftItem')->name('cart.add-draft-item');
Route::patch('cart/update-draft-item/{draftKey}', 'InvoiceDraftController@updateDraftItem')->name('cart.update-draft-item');
Route::patch('cart/{draftKey}/proccess', 'InvoiceDraftController@proccess')->name('cart.draft-proccess');
Route::delete('cart/remove-draft-item/{draftKey}', 'InvoiceDraftController@removeDraftItem')->name('cart.remove-draft-item');
Route::delete('cart/empty/{draftKey}', 'InvoiceDraftController@empty')->name('cart.empty');
Route::delete('cart/remove', 'InvoiceDraftController@remove')->name('cart.remove');
Route::delete('cart/destroy', 'InvoiceDraftController@destroy')->name('cart.destroy');
/*
* Invoices Routes
*/
Route::get('invoices/{invoice}', ['as' => 'invoices.show', 'uses' => 'InvoicesController@show']);
});

169
tests/Feature/InvoiceEntryTest.php

@ -0,0 +1,169 @@
<?php
namespace Tests\Feature;
use App\Entities\Projects\Project;
use App\Services\InvoiceDrafts\InvoiceDraft;
use App\Services\InvoiceDrafts\InvoiceDraftCollection;
use App\Services\InvoiceDrafts\Item;
use Tests\TestCase;
class InvoiceEntryTest extends TestCase
{
/** @test */
public function user_can_visit_invoice_drafts_page()
{
$this->adminUserSigningIn();
// Add new draft to collection
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$this->visit(route('invoices.create'));
$this->assertViewHas('draft', $draft);
}
/** @test */
public function user_can_create_invoice_draft_by_invoice_create_button()
{
$this->adminUserSigningIn();
$this->visit(route('invoices.create'));
$this->press(trans('invoice.create'));
$cart = new InvoiceDraftCollection();
$draft = $cart->content()->last();
$this->seePageIs(route('invoices.create', $draft->draftKey));
}
/** @test */
public function user_can_add_item_to_cash_draft()
{
$this->adminUserSigningIn();
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$this->visit(route('invoices.create', [$draft->draftKey]));
$this->type('Testing deskripsi invoice item', 'description');
$this->type(2000, 'amount');
$this->press('add-item');
$this->see(trans('invoice.item_added'));
$this->type('Testing deskripsi invoice item', 'description');
$this->type(3000, 'amount');
$this->press('add-item');
$this->seePageIs(route('invoices.create', $draft->draftKey));
$this->assertEquals(5000, $draft->getTotal());
$this->see(formatRp(5000));
}
/** @test */
public function user_can_update_item_attribute()
{
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item1 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$item2 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 2000]);
// Add items to draft
$cart->addItemToDraft($draft->draftKey, $item1);
$cart->addItemToDraft($draft->draftKey, $item2);
$this->adminUserSigningIn();
$this->visit(route('invoices.create', $draft->draftKey));
$this->submitForm('update-item-0', [
'item_key' => 0,
'description' => 'Testing deskripsi Update',
'amount' => 100,
]);
$this->submitForm('update-item-1', [
'item_key' => 1,
'description' => 'Testing deskripsi Update',
'amount' => 100,
]);
$this->assertEquals(200, $draft->getTotal());
$this->see(formatRp($draft->getTotal()));
}
/** @test */
public function user_can_update_draft_transaction_detail_and_get_confirm_page()
{
$project = factory(Project::class)->create();
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item1 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$item2 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 2000]);
// Add items to draft
$cart->addItemToDraft($draft->draftKey, $item1);
$cart->addItemToDraft($draft->draftKey, $item2);
$this->adminUserSigningIn();
$this->visit(route('invoices.create', $draft->draftKey));
$this->type($project->id, 'project_id');
$this->type('catatan', 'notes');
$this->press(trans('invoice.proccess'));
$this->seePageIs(route('invoices.create', [$draft->draftKey, 'action' => 'confirm']));
$this->see(trans('invoice.confirm'));
$this->see($project->name);
$this->see($draft->notes);
$this->see(formatRp(3000));
$this->seeElement('input', ['id' => 'save-invoice-draft']);
}
/** @test */
public function user_can_save_transaction_if_draft_is_completed()
{
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item1 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$item2 = new Item(['description' => 'Deskripsi item invoice', 'amount' => 2000]);
$project = factory(Project::class)->create();
// Add items to draft
$cart->addItemToDraft($draft->draftKey, $item1);
$cart->addItemToDraft($draft->draftKey, $item2);
$draftAttributes = [
'project_id' => $project->id,
'notes' => 'Catatan',
];
$cart->updateDraftAttributes($draft->draftKey, $draftAttributes);
$user = $this->adminUserSigningIn();
$this->visit(route('invoices.create', [$draft->draftKey, 'action' => 'confirm']));
$this->press(trans('invoice.save'));
// $this->seePageIs(route('invoices.show', date('ym').'0001'));
// $this->see(trans('invoice.created', ['invoice_no' => date('ym').'0001']));
$this->seeInDatabase('invoices', [
'invoice_no' => date('ym').'0001',
'items' => '[{"description":"Deskripsi item invoice","amount":1000},{"description":"Deskripsi item invoice","amount":2000}]',
'project_id' => $project->id,
'amount' => 3000,
'notes' => 'Catatan',
'user_id' => $user->id,
'status_id' => 1,
]);
}
}

152
tests/Unit/InvoiceDraftCollectionTest.php

@ -0,0 +1,152 @@
<?php
namespace Tests\Unit;
use App\Services\InvoiceDrafts\Item;
use App\Services\InvoiceDrafts\InvoiceDraft;
use App\Services\InvoiceDrafts\InvoiceDraftCollection;
use Tests\TestCase;
class InvoiceDraftCollectionTest extends TestCase
{
/** @test */
public function it_has_a_default_instance()
{
$cart = new InvoiceDraftCollection();
$this->assertEquals('drafts', $cart->currentInstance());
}
/** @test */
public function it_can_have_multiple_instances()
{
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$cart->instance('wishlist')->add($draft);
$this->assertCount(1, $cart->instance('drafts')->content());
$this->assertCount(1, $cart->instance('wishlist')->content());
}
/** @test */
public function cart_collection_consist_of_invoice_draft()
{
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$this->assertCount(1, $cart->content());
$this->assertTrue($cart->hasContent());
}
/** @test */
public function it_can_get_a_draft_by_key()
{
$draft = new InvoiceDraft();
$cart = new InvoiceDraftCollection();
$cart->add($draft);
$gottenDraft = $cart->get($draft->draftKey);
$invalidDraft = $cart->get('random_key');
$this->assertEquals($draft, $gottenDraft);
$this->assertNull($invalidDraft);
}
/** @test */
public function it_can_remove_draft_from_draft_collection()
{
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$this->assertCount(1, $cart->content());
$cart->removeDraft($cart->content()->keys()->last());
$this->assertCount(0, $cart->content());
}
/** @test */
public function it_can_be_empty_out()
{
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$cart->add($draft);
$cart->add($draft);
$this->assertCount(3, $cart->content());
$cart->destroy();
$this->assertCount(0, $cart->content());
$this->assertTrue($cart->isEmpty());
}
/** @test */
public function it_has_content_keys()
{
$cart = new InvoiceDraftCollection();
$draft = new InvoiceDraft();
$cart->add($draft);
$this->assertCount(1, $cart->keys());
$cart->removeDraft($cart->content()->keys()->last());
$this->assertCount(0, $cart->keys());
}
/** @test */
public function it_can_add_item_to_draft()
{
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$cart->addItemToDraft($draft->draftKey, $item);
$cart->addItemToDraft($draft->draftKey, $item);
$this->assertEquals(2000, $draft->getTotal());
$this->assertEquals(2, $draft->getItemsCount());
}
/** @test */
public function it_can_remove_item_from_draft()
{
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$cart->addItemToDraft($draft->draftKey, $item);
$this->assertCount(1, $draft->items());
$cart->removeItemFromDraft($draft->draftKey, 0);
$this->assertCount(0, $draft->items());
$this->assertEquals(0, $draft->getTotal());
}
/** @test */
public function it_can_update_an_item_of_draft()
{
$cart = new InvoiceDraftCollection();
$draft = $cart->add(new InvoiceDraft());
$item = new Item(['description' => 'Deskripsi item invoice', 'amount' => 1000]);
$cart->addItemToDraft($draft->draftKey, $item);
$this->assertCount(1, $draft->items());
$this->assertEquals(1000, $draft->getTotal());
$newItemData = [
'amount' => 100,
];
$cart->updateDraftItem($draft->draftKey, 0, $newItemData);
$this->assertEquals(100, $draft->getTotal());
}
}
Loading…
Cancel
Save