Release 1.20.3 (#3340)
* fix edit timesheet link * fix drag & drop creates record for wrong user * fix search with multiple bindings * hide user switcher in calendar if there is only one user to choose * make quick entry responsive for mobile-only users * mark invoices as exported by default * fix serialization deprecation warning * fix duration calculation for fixed rate entries * updated composer packages * fix checkbox for horizontal forms * support pdfContext for PDF invoice templates
This commit is contained in:
@@ -14,6 +14,13 @@ form.form-narrow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark as exported checkbox in export and invoice create screen */
|
||||||
|
.form-horizontal {
|
||||||
|
.checkbox {
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* bootstrap3 hack because the filter look plain ugly without it (see report: project month) */
|
/* bootstrap3 hack because the filter look plain ugly without it (see report: project month) */
|
||||||
.checkbox-menu li label {
|
.checkbox-menu li label {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"doctrine/doctrine-bundle": "^2.0",
|
"doctrine/doctrine-bundle": "^2.0",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||||
"doctrine/orm": "^2.8",
|
"doctrine/orm": "^2.8",
|
||||||
|
"doctrine/persistence": "^2",
|
||||||
"erusev/parsedown": "^1.6",
|
"erusev/parsedown": "^1.6",
|
||||||
"friendsofsymfony/rest-bundle": "^3.0",
|
"friendsofsymfony/rest-bundle": "^3.0",
|
||||||
"gedmo/doctrine-extensions": "^3.6",
|
"gedmo/doctrine-extensions": "^3.6",
|
||||||
|
|||||||
630
composer.lock
generated
630
composer.lock
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
|
|||||||
"build/app.0cc41cd4.js"
|
"build/app.0cc41cd4.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"build/app.7beab68a.css"
|
"build/app.4cf06f88.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"invoice": {
|
"invoice": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"build/app.css": "build/app.7beab68a.css",
|
"build/app.css": "build/app.4cf06f88.css",
|
||||||
"build/app.js": "build/app.0cc41cd4.js",
|
"build/app.js": "build/app.0cc41cd4.js",
|
||||||
"build/invoice.css": "build/invoice.ccdecd42.css",
|
"build/invoice.css": "build/invoice.ccdecd42.css",
|
||||||
"build/invoice.js": "build/invoice.19f36eca.js",
|
"build/invoice.js": "build/invoice.19f36eca.js",
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ class Constants
|
|||||||
/**
|
/**
|
||||||
* The current release version
|
* The current release version
|
||||||
*/
|
*/
|
||||||
public const VERSION = '1.20.2';
|
public const VERSION = '1.20.3';
|
||||||
/**
|
/**
|
||||||
* The current release: major * 10000 + minor * 100 + patch
|
* The current release: major * 10000 + minor * 100 + patch
|
||||||
*/
|
*/
|
||||||
public const VERSION_ID = 12002;
|
public const VERSION_ID = 12003;
|
||||||
/**
|
/**
|
||||||
* The current release status, either "stable" or "dev"
|
* The current release status, either "stable" or "dev"
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ class CalendarController extends AbstractController
|
|||||||
$profile = $values['user'];
|
$profile = $values['user'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$form = $form->createView();
|
||||||
|
|
||||||
|
// hide if the current user is the only available one
|
||||||
|
if (\count($form->offsetGet('user')->vars['choices']) < 2) {
|
||||||
|
$form = null;
|
||||||
|
$profile = $this->getUser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$mode = $this->service->getActiveMode();
|
$mode = $this->service->getActiveMode();
|
||||||
@@ -80,7 +88,7 @@ class CalendarController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('calendar/user.html.twig', [
|
return $this->render('calendar/user.html.twig', [
|
||||||
'form' => ($form === null ? null : $form->createView()),
|
'form' => $form,
|
||||||
'user' => $profile,
|
'user' => $profile,
|
||||||
'config' => $config,
|
'config' => $config,
|
||||||
'dragAndDrop' => $dragAndDrop,
|
'dragAndDrop' => $dragAndDrop,
|
||||||
|
|||||||
@@ -1046,6 +1046,17 @@ class User implements UserInterface, EquatableInterface, \Serializable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'username' => $this->username,
|
||||||
|
'enabled' => $this->enabled,
|
||||||
|
'email' => $this->email,
|
||||||
|
'password' => $this->password,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@@ -1060,6 +1071,18 @@ class User implements UserInterface, EquatableInterface, \Serializable
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $data): void
|
||||||
|
{
|
||||||
|
if (!\array_key_exists('id', $data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->id = $data['id'];
|
||||||
|
$this->username = $data['username'];
|
||||||
|
$this->enabled = $data['enabled'];
|
||||||
|
$this->email = $data['email'];
|
||||||
|
$this->password = $data['password'];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ abstract class AbstractCalculator
|
|||||||
{
|
{
|
||||||
$time = 0;
|
$time = 0;
|
||||||
foreach ($this->model->getEntries() as $entry) {
|
foreach ($this->model->getEntries() as $entry) {
|
||||||
if (null === $entry->getFixedRate() && null !== $entry->getDuration()) {
|
if (null !== $entry->getDuration()) {
|
||||||
$time += $entry->getDuration();
|
$time += $entry->getDuration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ abstract class AbstractTwigRenderer implements RendererInterface
|
|||||||
$this->twig = $twig;
|
$this->twig = $twig;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderTwigTemplate(InvoiceDocument $document, InvoiceModel $model): string
|
protected function renderTwigTemplate(InvoiceDocument $document, InvoiceModel $model, array $options = []): string
|
||||||
{
|
{
|
||||||
$language = $model->getTemplate()->getLanguage();
|
$language = $model->getTemplate()->getLanguage();
|
||||||
$formatLocale = $model->getFormatter()->getLocale();
|
$formatLocale = $model->getFormatter()->getLocale();
|
||||||
@@ -42,14 +42,14 @@ abstract class AbstractTwigRenderer implements RendererInterface
|
|||||||
$entries[] = $model->itemToArray($entry);
|
$entries[] = $model->itemToArray($entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = [
|
$options = array_merge([
|
||||||
// model should not be used in the future, but we can likely not remove it
|
// model should not be used in the future, but we can likely not remove it
|
||||||
'model' => $model,
|
'model' => $model,
|
||||||
// new since 1.16.7 - templates should only use the pre-generated values
|
// new since 1.16.7 - templates should only use the pre-generated values
|
||||||
'invoice' => $model->toArray(),
|
'invoice' => $model->toArray(),
|
||||||
// new since 1.19.5 - templates should only use the pre-generated values
|
// new since 1.19.5 - templates should only use the pre-generated values
|
||||||
'entries' => $entries
|
'entries' => $entries
|
||||||
];
|
], $options);
|
||||||
|
|
||||||
return $this->renderTwigTemplateWithLanguage($this->twig, $template, $options, $language, $formatLocale);
|
return $this->renderTwigTemplateWithLanguage($this->twig, $template, $options, $language, $formatLocale);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
namespace App\Invoice\Renderer;
|
namespace App\Invoice\Renderer;
|
||||||
|
|
||||||
use App\Entity\InvoiceDocument;
|
use App\Entity\InvoiceDocument;
|
||||||
|
use App\Export\ExportContext;
|
||||||
use App\Invoice\InvoiceFilename;
|
use App\Invoice\InvoiceFilename;
|
||||||
use App\Invoice\InvoiceModel;
|
use App\Invoice\InvoiceModel;
|
||||||
use App\Utils\HtmlToPdfConverter;
|
use App\Utils\HtmlToPdfConverter;
|
||||||
@@ -37,16 +38,23 @@ final class PdfRenderer extends AbstractTwigRenderer
|
|||||||
|
|
||||||
public function render(InvoiceDocument $document, InvoiceModel $model): Response
|
public function render(InvoiceDocument $document, InvoiceModel $model): Response
|
||||||
{
|
{
|
||||||
$content = $this->renderTwigTemplate($document, $model);
|
$filename = new InvoiceFilename($model);
|
||||||
|
|
||||||
$content = $this->converter->convertToPdf($content, [
|
$context = new ExportContext();
|
||||||
'setAutoTopMargin' => 'pad',
|
$context->setOption('filename', $filename->getFilename());
|
||||||
'setAutoBottomMargin' => 'pad',
|
$context->setOption('setAutoTopMargin', 'pad');
|
||||||
'margin_top' => 12,
|
$context->setOption('setAutoBottomMargin', 'pad');
|
||||||
'margin_bottom' => 8,
|
$context->setOption('margin_top', '12');
|
||||||
]);
|
$context->setOption('margin_bottom', '8');
|
||||||
|
|
||||||
$filename = (string) new InvoiceFilename($model);
|
$content = $this->renderTwigTemplate($document, $model, ['pdfContext' => $context]);
|
||||||
|
$content = $this->converter->convertToPdf($content, $context->getOptions());
|
||||||
|
|
||||||
|
$filename = $context->getOption('filename');
|
||||||
|
if (empty($filename)) {
|
||||||
|
$filename = new InvoiceFilename($model);
|
||||||
|
$filename = $filename->getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
$response = new Response($content);
|
$response = new Response($content);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class InvoiceQuery extends TimesheetQuery
|
|||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $markAsExported = false;
|
private $markAsExported = true;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,7 @@ class InvoiceQuery extends TimesheetQuery
|
|||||||
'exported' => InvoiceQuery::STATE_NOT_EXPORTED,
|
'exported' => InvoiceQuery::STATE_NOT_EXPORTED,
|
||||||
'state' => self::STATE_STOPPED,
|
'state' => self::STATE_STOPPED,
|
||||||
'billable' => true,
|
'billable' => true,
|
||||||
'markAsExported' => false,
|
'markAsExported' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,36 +59,43 @@ trait RepositorySearchTrait
|
|||||||
$searchAnd = $qb->expr()->andX();
|
$searchAnd = $qb->expr()->andX();
|
||||||
|
|
||||||
if ($this->supportsMetaFields()) {
|
if ($this->supportsMetaFields()) {
|
||||||
|
$i = 0;
|
||||||
|
$a = 0;
|
||||||
|
$c = 0;
|
||||||
foreach ($searchTerm->getSearchFields() as $metaName => $metaValue) {
|
foreach ($searchTerm->getSearchFields() as $metaName => $metaValue) {
|
||||||
$and = $qb->expr()->andX();
|
$and = $qb->expr()->andX();
|
||||||
|
/** @var literal-string $alias */
|
||||||
|
$alias = 'meta' . $a++;
|
||||||
|
$paramName = 'metaName' . $i++;
|
||||||
|
$paramValue = 'metaValue' . $c++;
|
||||||
|
|
||||||
if ($metaValue === '*') {
|
if ($metaValue === '*') {
|
||||||
$qb->leftJoin($rootAlias . '.meta', 'meta');
|
$qb->leftJoin($rootAlias . '.meta', $alias);
|
||||||
$and->add($qb->expr()->eq('meta.name', ':metaName'));
|
$and->add($qb->expr()->eq($alias . '.name', ':' . $paramName));
|
||||||
$qb->setParameter('metaName', $metaName);
|
$qb->setParameter($paramName, $metaName);
|
||||||
$and->add($qb->expr()->isNotNull('meta.value'));
|
$and->add($qb->expr()->isNotNull($alias . '.value'));
|
||||||
} elseif ($metaValue === '~') {
|
} elseif ($metaValue === '~') {
|
||||||
$and->add(
|
$and->add(
|
||||||
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
|
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
|
||||||
);
|
);
|
||||||
} elseif ($metaValue === '' || $metaValue === null) {
|
} elseif ($metaValue === '' || $metaValue === null) {
|
||||||
$qb->leftJoin($rootAlias . '.meta', 'meta');
|
$qb->leftJoin($rootAlias . '.meta', $alias);
|
||||||
$and->add(
|
$and->add(
|
||||||
$qb->expr()->orX(
|
$qb->expr()->orX(
|
||||||
$qb->expr()->andX(
|
$qb->expr()->andX(
|
||||||
$qb->expr()->eq('meta.name', ':metaName'),
|
$qb->expr()->eq($alias . '.name', ':' . $paramName),
|
||||||
$qb->expr()->isNull('meta.value')
|
$qb->expr()->isNull($alias . '.value')
|
||||||
),
|
),
|
||||||
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
|
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$qb->setParameter('metaName', $metaName);
|
$qb->setParameter($paramName, $metaName);
|
||||||
} else {
|
} else {
|
||||||
$qb->leftJoin($rootAlias . '.meta', 'meta');
|
$qb->leftJoin($rootAlias . '.meta', $alias);
|
||||||
$and->add($qb->expr()->eq('meta.name', ':metaName'));
|
$and->add($qb->expr()->eq($alias . '.name', ':' . $paramName));
|
||||||
$and->add($qb->expr()->like('meta.value', ':metaValue'));
|
$and->add($qb->expr()->like($alias . '.value', ':' . $paramValue));
|
||||||
$qb->setParameter('metaName', $metaName);
|
$qb->setParameter($paramName, $metaName);
|
||||||
$qb->setParameter('metaValue', '%' . $metaValue . '%');
|
$qb->setParameter($paramValue, '%' . $metaValue . '%');
|
||||||
}
|
}
|
||||||
|
|
||||||
$searchAnd->add($and);
|
$searchAnd->add($and);
|
||||||
@@ -99,16 +106,18 @@ trait RepositorySearchTrait
|
|||||||
|
|
||||||
if ($searchTerm->hasSearchTerm() && \count($fields) > 0) {
|
if ($searchTerm->hasSearchTerm() && \count($fields) > 0) {
|
||||||
$or = $qb->expr()->orX();
|
$or = $qb->expr()->orX();
|
||||||
|
$i = 0;
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
$param = 'searchTerm' . $i++;
|
||||||
if (stripos($field, '.') === false) {
|
if (stripos($field, '.') === false) {
|
||||||
$field = $rootAlias . '.' . $field;
|
$field = $rootAlias . '.' . $field;
|
||||||
}
|
}
|
||||||
$or->add(
|
$or->add(
|
||||||
$qb->expr()->like($field, ':searchTerm'),
|
$qb->expr()->like($field, ':' . $param),
|
||||||
);
|
);
|
||||||
|
$qb->setParameter($param, '%' . $searchTerm->getSearchTerm() . '%');
|
||||||
}
|
}
|
||||||
$searchAnd->add($or);
|
$searchAnd->add($or);
|
||||||
$qb->setParameter('searchTerm', '%' . $searchTerm->getSearchTerm() . '%');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($searchAnd->count() > 0) {
|
if ($searchAnd->count() > 0) {
|
||||||
|
|||||||
@@ -69,12 +69,14 @@
|
|||||||
{% set calendarSelector = '#timesheet_calendar' %}
|
{% set calendarSelector = '#timesheet_calendar' %}
|
||||||
{% set createParams = '' %}
|
{% set createParams = '' %}
|
||||||
{% set createRoute = 'timesheet_create' %}
|
{% set createRoute = 'timesheet_create' %}
|
||||||
|
{% set editRoute = 'timesheet_edit' %}
|
||||||
{% set canDelete = is_granted('delete_own_timesheet') %}
|
{% set canDelete = is_granted('delete_own_timesheet') %}
|
||||||
{% set canCreate = is_granted('create_own_timesheet') %}
|
{% set canCreate = is_granted('create_own_timesheet') %}
|
||||||
{% set canEdit = is_granted('edit_own_timesheet') %}
|
{% set canEdit = is_granted('edit_own_timesheet') %}
|
||||||
{% if user != app.user %}
|
{% if user != app.user %}
|
||||||
{% set createParams = '&user=' ~ user.id %}
|
{% set createParams = '&user=' ~ user.id %}
|
||||||
{% set createRoute = 'admin_timesheet_create' %}
|
{% set createRoute = 'admin_timesheet_create' %}
|
||||||
|
{% set editRoute = 'admin_timesheet_edit' %}
|
||||||
{% set canDelete = is_granted('delete_other_timesheet') %}
|
{% set canDelete = is_granted('delete_other_timesheet') %}
|
||||||
{% set canCreate = is_granted('create_other_timesheet') %}
|
{% set canCreate = is_granted('create_other_timesheet') %}
|
||||||
{% set canEdit = is_granted('edit_other_timesheet') %}
|
{% set canEdit = is_granted('edit_other_timesheet') %}
|
||||||
@@ -303,6 +305,7 @@
|
|||||||
let source = entry.parentElement;
|
let source = entry.parentElement;
|
||||||
let plainData = entry.dataset.entry;
|
let plainData = entry.dataset.entry;
|
||||||
let data = JSON.parse(plainData);
|
let data = JSON.parse(plainData);
|
||||||
|
data.user = {{ user.id }};
|
||||||
let urlReplacer = JSON.parse(source.dataset.routeReplacer);
|
let urlReplacer = JSON.parse(source.dataset.routeReplacer);
|
||||||
let apiUrl = source.dataset.route;
|
let apiUrl = source.dataset.route;
|
||||||
|
|
||||||
@@ -491,7 +494,7 @@
|
|||||||
jsEvent.preventDefault();
|
jsEvent.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let editUrl = '{{ path('timesheet_edit', {id: '-XX-'}) }}'.replace('-XX-', eventObj.id);
|
let editUrl = '{{ path(editRoute, {id: '-XX-'}) }}'.replace('-XX-', eventObj.id);
|
||||||
kimai.getPlugin('modal').openUrlInModal(editUrl);
|
kimai.getPlugin('modal').openUrlInModal(editUrl);
|
||||||
},
|
},
|
||||||
{% if not is_punch_mode %}
|
{% if not is_punch_mode %}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
{% block box_title %}
|
{% block box_title %}
|
||||||
{{ form_widget(form.date) }}
|
{{ form_widget(form.date) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block box_body_class %}no-padding{% endblock %}
|
{% block box_body_class %}no-padding table-responsive{% endblock %}
|
||||||
{% block box_footer %}
|
{% block box_footer %}
|
||||||
<input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
|
<input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
|
||||||
<button type="button" class="btn btn-success add-item-link" data-collection-prototype="{{ form.rows.vars.id }}" data-collection-holder="ts-collection">
|
<button type="button" class="btn btn-success add-item-link" data-collection-prototype="{{ form.rows.vars.id }}" data-collection-holder="ts-collection">
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTest
|
|||||||
$this->assertEquals(19, $sut->getVat());
|
$this->assertEquals(19, $sut->getVat());
|
||||||
$this->assertEquals('EUR', $model->getCurrency());
|
$this->assertEquals('EUR', $model->getCurrency());
|
||||||
$this->assertEquals(2521.12, $sut->getSubtotal());
|
$this->assertEquals(2521.12, $sut->getSubtotal());
|
||||||
$this->assertEquals(4800, $sut->getTimeWorked());
|
$this->assertEquals(6600, $sut->getTimeWorked());
|
||||||
|
|
||||||
$entries = $sut->getEntries();
|
$entries = $sut->getEntries();
|
||||||
self::assertCount(4, $entries);
|
self::assertCount(4, $entries);
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTest
|
|||||||
$this->assertEquals(19, $sut->getVat());
|
$this->assertEquals(19, $sut->getVat());
|
||||||
$this->assertEquals('EUR', $model->getCurrency());
|
$this->assertEquals('EUR', $model->getCurrency());
|
||||||
$this->assertEquals(488.38, $sut->getSubtotal());
|
$this->assertEquals(488.38, $sut->getSubtotal());
|
||||||
$this->assertEquals(5400, $sut->getTimeWorked());
|
$this->assertEquals(5800, $sut->getTimeWorked());
|
||||||
$this->assertEquals(1, \count($sut->getEntries()));
|
$this->assertEquals(1, \count($sut->getEntries()));
|
||||||
|
|
||||||
/** @var InvoiceItem $result */
|
/** @var InvoiceItem $result */
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ class InvoiceQueryTest extends TimesheetQueryTest
|
|||||||
|
|
||||||
protected function assertMarkAsExported(InvoiceQuery $sut)
|
protected function assertMarkAsExported(InvoiceQuery $sut)
|
||||||
{
|
{
|
||||||
self::assertFalse($sut->isMarkAsExported());
|
|
||||||
|
|
||||||
$sut->setMarkAsExported(true);
|
|
||||||
self::assertTrue($sut->isMarkAsExported());
|
self::assertTrue($sut->isMarkAsExported());
|
||||||
|
|
||||||
|
$sut->setMarkAsExported(false);
|
||||||
|
self::assertFalse($sut->isMarkAsExported());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user