Skip to content

Commit

Permalink
Create meal ticket removal
Browse files Browse the repository at this point in the history
  • Loading branch information
mmarchois authored and Volubyl committed Apr 24, 2021
1 parent 30cd330 commit 64d4c63
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 49 deletions.
5 changes: 5 additions & 0 deletions client/src/components/Nav.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@
class="w-full"
href="human_resources/meal_tickets">{$_('human_resources.meal_tickets.title')}</a>
</li>
<li class="{subLinkClass}">
<a
class="w-full"
href="human_resources/meal_tickets">{$_('human_resources.meal_tickets.title')}</a>
</li>
<li class="{subLinkClass}">
<a
class="w-full"
Expand Down
3 changes: 1 addition & 2 deletions client/src/routes/crm/projects/_Table.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<thead>
<tr
class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50 dark:text-gray-400 dark:bg-gray-800">
<th class="px-4 py-3">{$_('crm.projects.customer')}</th>
<th class="px-4 py-3">{$_('crm.projects.name')}</th>
<th class="px-4 py-3">{$_('crm.projects.customer')}</th>
<th class="px-4 py-3">{$_('crm.projects.invoice_unit.title')}</th>
<th class="px-4 py-3">{$_('crm.projects.day_duration')}</th>
<th class="px-4 py-3">{$_('common.actions')}</th>
Expand All @@ -20,7 +20,6 @@
<tbody class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800">
{#each items as { id, name, dayDuration, customer, invoiceUnit } (id)}
<tr class="text-gray-700 dark:text-gray-400">
<td class="px-4 py-3 text-sm">{customer.name}</td>
<td class="px-4 py-3 text-sm">{name}</td>
<td class="px-4 py-3 text-sm">
{$_(`crm.projects.invoice_unit.${invoiceUnit}`)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { mock, instance, when, verify, deepEqual, anything } from 'ts-mockito';
import { User } from 'src/Domain/HumanResource/User/User.entity';
import { MealTicketRemovalRepository } from 'src/Infrastructure/HumanResource/MealTicket/Repository/MealTicketRemovalRepository';
import { IsMealTicketRemovalAlreadyExist } from 'src/Domain/HumanResource/MealTicket/Specification/IsMealTicketRemovalAlreadyExist';
import { CreateMealTicketRemovalCommandHandler } from './CreateMealTicketRemovalCommandHandler';
import { CreateMealTicketRemovalCommand } from './CreateMealTicketRemovalCommand';
import { MealTicketRemoval } from 'src/Domain/HumanResource/MealTicket/MealTicketRemoval.entity';
import { MealTicketRemovalAlreadyExistException } from 'src/Domain/HumanResource/MealTicket/Exception/MealTicketRemovalAlreadyExistException';

describe('CreateMealTicketRemovalCommandHandler', () => {
let mealTicketRemovalRepository: MealTicketRemovalRepository;
let isMealTicketRemovalAlreadyExist: IsMealTicketRemovalAlreadyExist;
let handler: CreateMealTicketRemovalCommandHandler;

const user = mock(User);
const mealTicketRemoval = mock(MealTicketRemoval);
const command = new CreateMealTicketRemovalCommand(
'2020-04-29',
'dejeuner offert',
instance(user)
);

beforeEach(() => {
mealTicketRemovalRepository = mock(MealTicketRemovalRepository);
isMealTicketRemovalAlreadyExist = mock(IsMealTicketRemovalAlreadyExist);

handler = new CreateMealTicketRemovalCommandHandler(
instance(mealTicketRemovalRepository),
instance(isMealTicketRemovalAlreadyExist)
);
});

it('testMealTicketRemovalSuccessfullyCreated', async () => {
when(
isMealTicketRemovalAlreadyExist.isSatisfiedBy(
instance(user),
deepEqual(new Date('2020-04-29'))
)
).thenResolve(false);
when(mealTicketRemoval.getId()).thenReturn(
'7c35d37c-b0e3-480d-bf6c-3dc1e094886f'
);
when(
mealTicketRemovalRepository.save(
deepEqual(
new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user))
)
)
).thenResolve(instance(mealTicketRemoval));

expect(await handler.execute(command)).toBe(
'7c35d37c-b0e3-480d-bf6c-3dc1e094886f'
);

verify(
isMealTicketRemovalAlreadyExist.isSatisfiedBy(
instance(user),
deepEqual(new Date('2020-04-29'))
)
).once();
verify(
mealTicketRemovalRepository.save(
deepEqual(
new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user))
)
)
).once();
});

it('testMealTicketRemovalAlreadyExist', async () => {
when(
isMealTicketRemovalAlreadyExist.isSatisfiedBy(
instance(user),
deepEqual(new Date('2020-04-29'))
)
).thenResolve(true);

try {
await handler.execute(command);
} catch (e) {
expect(e).toBeInstanceOf(MealTicketRemovalAlreadyExistException);
expect(e.message).toBe(
'human_resources.meal_ticket.meal_ticket_removal.errors.already_exist'
);
verify(
isMealTicketRemovalAlreadyExist.isSatisfiedBy(
instance(user),
deepEqual(new Date('2020-04-29'))
)
).once();
verify(mealTicketRemovalRepository.save(anything())).never();
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@ export class CreateMealTicketRemovalCommandHandler {
constructor(
@Inject('IMealTicketRemovalRepository')
private readonly mealTicketRemovalRepository: IMealTicketRemovalRepository,
private readonly isMealTicketRemovalAlreadyExist: IsMealTicketRemovalAlreadyExist,
private readonly isMealTicketRemovalAlreadyExist: IsMealTicketRemovalAlreadyExist
) {}

public async execute(command: CreateMealTicketRemovalCommand): Promise<string> {
public async execute(
command: CreateMealTicketRemovalCommand
): Promise<string> {
const { date, comment, user } = command;

if (
true ===
(await this.isMealTicketRemovalAlreadyExist.isSatisfiedBy(user, new Date(date)))
(await this.isMealTicketRemovalAlreadyExist.isSatisfiedBy(
user,
new Date(date)
))
) {
throw new MealTicketRemovalAlreadyExistException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ describe('CreateMealTicketRemovalCommandHandler', () => {
deepEqual(new Date('2020-04-29'))
)
).thenResolve(false);
when(mealTicketRemoval.getId()).thenReturn('7c35d37c-b0e3-480d-bf6c-3dc1e094886f');
when(mealTicketRemoval.getId()).thenReturn(
'7c35d37c-b0e3-480d-bf6c-3dc1e094886f'
);
when(
mealTicketRemovalRepository.save(
deepEqual(new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user)))
deepEqual(
new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user))
)
)
).thenResolve(instance(mealTicketRemoval));

Expand All @@ -56,7 +60,9 @@ describe('CreateMealTicketRemovalCommandHandler', () => {
).once();
verify(
mealTicketRemovalRepository.save(
deepEqual(new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user)))
deepEqual(
new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user))
)
)
).once();
});
Expand All @@ -73,7 +79,9 @@ describe('CreateMealTicketRemovalCommandHandler', () => {
await handler.execute(command);
} catch (e) {
expect(e).toBeInstanceOf(MealTicketRemovalAlreadyExistException);
expect(e.message).toBe('human_resources.meal_ticket.meal_ticket_removal.errors.already_exist');
expect(e.message).toBe(
'human_resources.meal_ticket.meal_ticket_removal.errors.already_exist'
);
verify(
isMealTicketRemovalAlreadyExist.isSatisfiedBy(
instance(user),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export class MealTicketRemovalAlreadyExistException extends Error {
constructor() {
super('human_resources.meal_ticket.meal_ticket_removal.errors.already_exist');
super(
'human_resources.meal_ticket.meal_ticket_removal.errors.already_exist'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ describe('MealTicketRemoval.entity', () => {
expect(mealTicketRemoval.getId()).toBe(undefined);
expect(mealTicketRemoval.getDate()).toBe('2020-04-26');
expect(mealTicketRemoval.getUser()).toBe(instance(user));
expect(mealTicketRemoval.getComment()).toBe('Dejeuner offert à la conférence');
expect(mealTicketRemoval.getComment()).toBe(
'Dejeuner offert à la conférence'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ export class MealTicketRemoval {
@PrimaryGeneratedColumn('uuid')
private id: string;

@Column({type: 'timestamp', nullable: false})
@Column({ type: 'timestamp', nullable: false })
private date: string;

@Column({type: 'varchar', nullable: false})
@Column({ type: 'varchar', nullable: false })
private comment: string;

@ManyToOne(type => User, {nullable: false, onDelete: 'CASCADE'})
@ManyToOne(type => User, { nullable: false, onDelete: 'CASCADE' })
private user: User;

constructor(date: string, comment: string, user: User) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ import { MealTicketRemoval } from '../MealTicketRemoval.entity';

export interface IMealTicketRemovalRepository {
save(MealTicketRemoval: MealTicketRemoval): Promise<MealTicketRemoval>;
findOneByUserAndDate(user: User, date: Date): Promise<MealTicketRemoval | undefined>;
findOneByUserAndDate(
user: User,
date: Date
): Promise<MealTicketRemoval | undefined>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export class IsMealTicketRemovalAlreadyExist {

public async isSatisfiedBy(user: User, date: Date): Promise<boolean> {
return (
(await this.mealTicketRemovalRepository.findOneByUserAndDate(user, date)) instanceof
MealTicketRemoval
(await this.mealTicketRemovalRepository.findOneByUserAndDate(
user,
date
)) instanceof MealTicketRemoval
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ describe('IsMealTicketRemovalAlreadyExist', () => {
it('testMealTicketRemovalAlreadyExist', async () => {
when(
mealTicketRemovalRepository.findOneByUserAndDate(instance(user), date)
).thenResolve(new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user)));
).thenResolve(
new MealTicketRemoval('2020-04-29', 'dejeuner offert', instance(user))
);
expect(
await isMealTicketRemovalAlreadyExist.isSatisfiedBy(instance(user), date)
).toBe(true);
verify(mealTicketRemovalRepository.findOneByUserAndDate(instance(user), date)).once();
verify(
mealTicketRemovalRepository.findOneByUserAndDate(instance(user), date)
).once();
});

it('testMealTicketRemovalDoesntExist', async () => {
Expand All @@ -34,6 +38,8 @@ describe('IsMealTicketRemovalAlreadyExist', () => {
expect(
await isMealTicketRemovalAlreadyExist.isSatisfiedBy(instance(user), date)
).toBe(false);
verify(mealTicketRemovalRepository.findOneByUserAndDate(instance(user), date)).once();
verify(
mealTicketRemovalRepository.findOneByUserAndDate(instance(user), date)
).once();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ import { Cooperative } from 'src/Domain/Settings/Cooperative.entity';
GetFairCalendarOverview
]
})
export class FairCalendarModule { }
export class FairCalendarModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class CreateMealTicketRemovalAction {

@Post()
@Roles(UserRole.COOPERATOR, UserRole.EMPLOYEE)
@ApiOperation({summary: 'Create new meal ticket removal'})
@ApiOperation({ summary: 'Create new meal ticket removal' })
public async index(
@Body() { date, comment }: MealTicketRemovalDTO,
@LoggedUser() user: User
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('MealTicketRemovalDTO', () => {
isNotEmpty: 'date should not be empty'
});
expect(validation[1].constraints).toMatchObject({
isNotEmpty: 'comment should not be empty',
isNotEmpty: 'comment should not be empty'
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import { MealTicketRemoval } from 'src/Domain/HumanResource/MealTicket/MealTicke
import { IMealTicketRemovalRepository } from 'src/Domain/HumanResource/MealTicket/Repository/IMealTicketRemovalRepository';
import { User } from 'src/Domain/HumanResource/User/User.entity';

export class MealTicketRemovalRepository implements IMealTicketRemovalRepository {
export class MealTicketRemovalRepository
implements IMealTicketRemovalRepository {
constructor(
@InjectRepository(MealTicketRemoval)
private readonly repository: Repository<MealTicketRemoval>
) {}

public save(mealTicketRemoval: MealTicketRemoval): Promise<MealTicketRemoval> {
public save(
mealTicketRemoval: MealTicketRemoval
): Promise<MealTicketRemoval> {
return this.repository.save(mealTicketRemoval);
}

Expand All @@ -26,7 +29,9 @@ export class MealTicketRemovalRepository implements IMealTicketRemovalRepository
.createQueryBuilder('mealTicketRemoval')
.select(['mealTicketRemoval.id'])
.where('mealTicketRemoval.user = :userId', { userId: user.getId() })
.andWhere('extract(month FROM mealTicketRemoval.date) = :month', { month })
.andWhere('extract(month FROM mealTicketRemoval.date) = :month', {
month
})
.andWhere('extract(year FROM mealTicketRemoval.date) = :year', { year })
.andWhere('extract(day FROM mealTicketRemoval.date) = :day', { day })
.getOne();
Expand Down
Loading

0 comments on commit 64d4c63

Please sign in to comment.