Add church management features: Implement endpoints for church overview, available positions, supervised applications, and application processing in FalukantService and FalukantController. Update router to include new routes for these functionalities, enhancing church-related operations.
This commit is contained in:
@@ -140,6 +140,17 @@ class FalukantController {
|
|||||||
const { characterId: childId, firstName } = req.body;
|
const { characterId: childId, firstName } = req.body;
|
||||||
return this.service.baptise(userId, childId, firstName);
|
return this.service.baptise(userId, childId, firstName);
|
||||||
});
|
});
|
||||||
|
this.getChurchOverview = this._wrapWithUser((userId) => this.service.getChurchOverview(userId));
|
||||||
|
this.getAvailableChurchPositions = this._wrapWithUser((userId) => this.service.getAvailableChurchPositions(userId));
|
||||||
|
this.getSupervisedApplications = this._wrapWithUser((userId) => this.service.getSupervisedApplications(userId));
|
||||||
|
this.applyForChurchPosition = this._wrapWithUser((userId, req) => {
|
||||||
|
const { officeTypeId, regionId } = req.body;
|
||||||
|
return this.service.applyForChurchPosition(userId, officeTypeId, regionId);
|
||||||
|
});
|
||||||
|
this.decideOnChurchApplication = this._wrapWithUser((userId, req) => {
|
||||||
|
const { applicationId, decision } = req.body;
|
||||||
|
return this.service.decideOnChurchApplication(userId, applicationId, decision);
|
||||||
|
});
|
||||||
|
|
||||||
this.getEducation = this._wrapWithUser((userId) => this.service.getEducation(userId));
|
this.getEducation = this._wrapWithUser((userId) => this.service.getEducation(userId));
|
||||||
this.sendToSchool = this._wrapWithUser((userId, req) => {
|
this.sendToSchool = this._wrapWithUser((userId, req) => {
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ router.post('/party', falukantController.createParty);
|
|||||||
router.get('/party', falukantController.getParties);
|
router.get('/party', falukantController.getParties);
|
||||||
router.get('/family/notbaptised', falukantController.getNotBaptisedChildren);
|
router.get('/family/notbaptised', falukantController.getNotBaptisedChildren);
|
||||||
router.post('/church/baptise', falukantController.baptise);
|
router.post('/church/baptise', falukantController.baptise);
|
||||||
|
router.get('/church/overview', falukantController.getChurchOverview);
|
||||||
|
router.get('/church/positions/available', falukantController.getAvailableChurchPositions);
|
||||||
|
router.get('/church/applications/supervised', falukantController.getSupervisedApplications);
|
||||||
|
router.post('/church/positions/apply', falukantController.applyForChurchPosition);
|
||||||
|
router.post('/church/applications/decide', falukantController.decideOnChurchApplication);
|
||||||
router.get('/education', falukantController.getEducation);
|
router.get('/education', falukantController.getEducation);
|
||||||
router.post('/education', falukantController.sendToSchool);
|
router.post('/education', falukantController.sendToSchool);
|
||||||
router.get('/bank/overview', falukantController.getBankOverview);
|
router.get('/bank/overview', falukantController.getBankOverview);
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ import Credit from '../models/falukant/data/credit.js';
|
|||||||
import TitleRequirement from '../models/falukant/type/title_requirement.js';
|
import TitleRequirement from '../models/falukant/type/title_requirement.js';
|
||||||
import HealthActivity from '../models/falukant/log/health_activity.js';
|
import HealthActivity from '../models/falukant/log/health_activity.js';
|
||||||
import Election from '../models/falukant/data/election.js';
|
import Election from '../models/falukant/data/election.js';
|
||||||
|
import ChurchOffice from '../models/falukant/data/church_office.js';
|
||||||
|
import ChurchOfficeType from '../models/falukant/type/church_office_type.js';
|
||||||
|
import ChurchApplication from '../models/falukant/data/church_application.js';
|
||||||
import PoliticalOfficeType from '../models/falukant/type/political_office_type.js';
|
import PoliticalOfficeType from '../models/falukant/type/political_office_type.js';
|
||||||
import Candidate from '../models/falukant/data/candidate.js';
|
import Candidate from '../models/falukant/data/candidate.js';
|
||||||
import Vote from '../models/falukant/data/vote.js';
|
import Vote from '../models/falukant/data/vote.js';
|
||||||
@@ -4820,6 +4823,480 @@ class FalukantService extends BaseService {
|
|||||||
all: mapped
|
all: mapped
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getChurchOverview(hashedUserId) {
|
||||||
|
const user = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const character = await FalukantCharacter.findOne({
|
||||||
|
where: { userId: user.id },
|
||||||
|
attributes: ['id', 'regionId']
|
||||||
|
});
|
||||||
|
if (!character) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle relevanten Regionen (Region + Eltern) laden
|
||||||
|
const relevantRegionIds = await this.getRegionAndParentIds(character.regionId);
|
||||||
|
|
||||||
|
// Aktuell besetzte Kirchenämter in diesen Regionen laden
|
||||||
|
const offices = await ChurchOffice.findAll({
|
||||||
|
where: {
|
||||||
|
regionId: {
|
||||||
|
[Op.in]: relevantRegionIds
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'type',
|
||||||
|
attributes: ['name', 'hierarchyLevel']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RegionData,
|
||||||
|
as: 'region',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'holder',
|
||||||
|
attributes: ['id', 'gender'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: FalukantPredefineFirstname,
|
||||||
|
as: 'definedFirstName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantPredefineLastname,
|
||||||
|
as: 'definedLastName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: TitleOfNobility,
|
||||||
|
as: 'nobleTitle',
|
||||||
|
attributes: ['labelTr']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'supervisor',
|
||||||
|
attributes: ['id', 'gender'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: FalukantPredefineFirstname,
|
||||||
|
as: 'definedFirstName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantPredefineLastname,
|
||||||
|
as: 'definedLastName',
|
||||||
|
attributes: ['name']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [
|
||||||
|
[{ model: ChurchOfficeType, as: 'type' }, 'hierarchyLevel', 'DESC'],
|
||||||
|
[{ model: RegionData, as: 'region' }, 'name', 'ASC']
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return offices.map(office => {
|
||||||
|
const o = office.get({ plain: true });
|
||||||
|
return {
|
||||||
|
id: o.id,
|
||||||
|
officeType: {
|
||||||
|
name: o.type?.name
|
||||||
|
},
|
||||||
|
region: {
|
||||||
|
name: o.region?.name
|
||||||
|
},
|
||||||
|
character: o.holder
|
||||||
|
? {
|
||||||
|
id: o.holder.id,
|
||||||
|
name: `${o.holder.definedFirstName?.name || ''} ${o.holder.definedLastName?.name || ''}`.trim(),
|
||||||
|
gender: o.holder.gender,
|
||||||
|
title: o.holder.nobleTitle?.labelTr
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
supervisor: o.supervisor
|
||||||
|
? {
|
||||||
|
id: o.supervisor.id,
|
||||||
|
name: `${o.supervisor.definedFirstName?.name || ''} ${o.supervisor.definedLastName?.name || ''}`.trim()
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAvailableChurchPositions(hashedUserId) {
|
||||||
|
const user = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const character = await FalukantCharacter.findOne({
|
||||||
|
where: { userId: user.id },
|
||||||
|
attributes: ['id', 'regionId']
|
||||||
|
});
|
||||||
|
if (!character) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle relevanten Regionen (Region + Eltern) laden
|
||||||
|
const relevantRegionIds = await this.getRegionAndParentIds(character.regionId);
|
||||||
|
|
||||||
|
// Alle Kirchenamt-Typen laden
|
||||||
|
const officeTypes = await ChurchOfficeType.findAll({
|
||||||
|
order: [['hierarchyLevel', 'ASC']]
|
||||||
|
});
|
||||||
|
|
||||||
|
const availablePositions = [];
|
||||||
|
|
||||||
|
for (const officeType of officeTypes) {
|
||||||
|
// Finde den RegionType für diesen officeType
|
||||||
|
const regionType = await RegionType.findOne({
|
||||||
|
where: { labelTr: officeType.regionType }
|
||||||
|
});
|
||||||
|
if (!regionType) continue;
|
||||||
|
|
||||||
|
// Finde alle Regionen dieses Typs in den relevanten Regionen
|
||||||
|
const regions = await RegionData.findAll({
|
||||||
|
where: {
|
||||||
|
id: { [Op.in]: relevantRegionIds },
|
||||||
|
regionTypeId: regionType.id
|
||||||
|
},
|
||||||
|
attributes: ['id', 'name']
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const region of regions) {
|
||||||
|
// Zähle besetzte Positionen dieses Typs in dieser Region
|
||||||
|
const occupiedCount = await ChurchOffice.count({
|
||||||
|
where: {
|
||||||
|
officeTypeId: officeType.id,
|
||||||
|
regionId: region.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const availableSeats = officeType.seatsPerRegion - occupiedCount;
|
||||||
|
|
||||||
|
if (availableSeats > 0) {
|
||||||
|
// Finde den Supervisor (höheres Amt in derselben Region oder Eltern-Region)
|
||||||
|
let supervisor = null;
|
||||||
|
const higherOfficeTypeIds = await ChurchOfficeType.findAll({
|
||||||
|
where: {
|
||||||
|
hierarchyLevel: { [Op.gt]: officeType.hierarchyLevel }
|
||||||
|
},
|
||||||
|
attributes: ['id']
|
||||||
|
}).then(types => types.map(t => t.id));
|
||||||
|
|
||||||
|
if (higherOfficeTypeIds.length > 0) {
|
||||||
|
const supervisorOffice = await ChurchOffice.findOne({
|
||||||
|
where: {
|
||||||
|
regionId: region.id,
|
||||||
|
officeTypeId: { [Op.in]: higherOfficeTypeIds }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'type',
|
||||||
|
attributes: ['hierarchyLevel']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'holder',
|
||||||
|
attributes: ['id']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [
|
||||||
|
[{ model: ChurchOfficeType, as: 'type' }, 'hierarchyLevel', 'ASC']
|
||||||
|
],
|
||||||
|
limit: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
if (supervisorOffice && supervisorOffice.holder) {
|
||||||
|
supervisor = {
|
||||||
|
id: supervisorOffice.holder.id,
|
||||||
|
name: 'Supervisor' // Wird später geladen falls nötig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supervisorOffice && supervisorOffice.holder) {
|
||||||
|
supervisor = {
|
||||||
|
id: supervisorOffice.holder.id,
|
||||||
|
name: 'Supervisor' // Wird später geladen falls nötig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
availablePositions.push({
|
||||||
|
id: officeType.id, // Verwende officeTypeId als ID für die Frontend-Identifikation
|
||||||
|
officeType: {
|
||||||
|
name: officeType.name
|
||||||
|
},
|
||||||
|
region: {
|
||||||
|
name: region.name,
|
||||||
|
id: region.id
|
||||||
|
},
|
||||||
|
regionId: region.id,
|
||||||
|
availableSeats: availableSeats,
|
||||||
|
supervisor: supervisor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availablePositions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSupervisedApplications(hashedUserId) {
|
||||||
|
const user = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const character = await FalukantCharacter.findOne({
|
||||||
|
where: { userId: user.id },
|
||||||
|
attributes: ['id']
|
||||||
|
});
|
||||||
|
if (!character) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finde alle Kirchenämter, die dieser Charakter hält
|
||||||
|
const heldOffices = await ChurchOffice.findAll({
|
||||||
|
where: { characterId: character.id },
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'type',
|
||||||
|
attributes: ['id', 'hierarchyLevel']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (heldOffices.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finde alle niedrigeren Ämter, die dieser Charakter superviden kann
|
||||||
|
const maxHierarchyLevel = Math.max(...heldOffices.map(o => o.type.hierarchyLevel));
|
||||||
|
const supervisedOfficeTypeIds = await ChurchOfficeType.findAll({
|
||||||
|
where: {
|
||||||
|
hierarchyLevel: { [Op.lt]: maxHierarchyLevel }
|
||||||
|
},
|
||||||
|
attributes: ['id']
|
||||||
|
}).then(types => types.map(t => t.id));
|
||||||
|
|
||||||
|
// Finde alle Bewerbungen für diese Ämter, bei denen dieser Charakter Supervisor ist
|
||||||
|
const applications = await ChurchApplication.findAll({
|
||||||
|
where: {
|
||||||
|
supervisorId: character.id,
|
||||||
|
status: 'pending',
|
||||||
|
officeTypeId: { [Op.in]: supervisedOfficeTypeIds }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'officeType',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: RegionData,
|
||||||
|
as: 'region',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'applicant',
|
||||||
|
attributes: ['id', 'gender', 'age'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: FalukantPredefineFirstname,
|
||||||
|
as: 'definedFirstName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantPredefineLastname,
|
||||||
|
as: 'definedLastName',
|
||||||
|
attributes: ['name']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: TitleOfNobility,
|
||||||
|
as: 'nobleTitle',
|
||||||
|
attributes: ['labelTr']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [['createdAt', 'DESC']]
|
||||||
|
});
|
||||||
|
|
||||||
|
return applications.map(app => {
|
||||||
|
const a = app.get({ plain: true });
|
||||||
|
return {
|
||||||
|
id: a.id,
|
||||||
|
officeType: {
|
||||||
|
name: a.officeType?.name
|
||||||
|
},
|
||||||
|
region: {
|
||||||
|
name: a.region?.name
|
||||||
|
},
|
||||||
|
applicant: {
|
||||||
|
id: a.applicant.id,
|
||||||
|
name: `${a.applicant.definedFirstName?.name || ''} ${a.applicant.definedLastName?.name || ''}`.trim(),
|
||||||
|
gender: a.applicant.gender,
|
||||||
|
age: a.applicant.age,
|
||||||
|
title: a.applicant.nobleTitle?.labelTr
|
||||||
|
},
|
||||||
|
createdAt: a.createdAt
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async applyForChurchPosition(hashedUserId, officeTypeId, regionId) {
|
||||||
|
const user = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const character = await FalukantCharacter.findOne({
|
||||||
|
where: { userId: user.id },
|
||||||
|
attributes: ['id', 'regionId']
|
||||||
|
});
|
||||||
|
if (!character) {
|
||||||
|
throw new Error('Character not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob Position verfügbar ist
|
||||||
|
const officeType = await ChurchOfficeType.findByPk(officeTypeId);
|
||||||
|
if (!officeType) {
|
||||||
|
throw new Error('Office type not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const occupiedCount = await ChurchOffice.count({
|
||||||
|
where: {
|
||||||
|
officeTypeId: officeTypeId,
|
||||||
|
regionId: regionId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (occupiedCount >= officeType.seatsPerRegion) {
|
||||||
|
throw new Error('No available seats');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finde Supervisor
|
||||||
|
const higherOfficeTypeIds = await ChurchOfficeType.findAll({
|
||||||
|
where: {
|
||||||
|
hierarchyLevel: { [Op.gt]: officeType.hierarchyLevel }
|
||||||
|
},
|
||||||
|
attributes: ['id']
|
||||||
|
}).then(types => types.map(t => t.id));
|
||||||
|
|
||||||
|
if (higherOfficeTypeIds.length === 0) {
|
||||||
|
throw new Error('No supervisor office type found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const supervisorOffice = await ChurchOffice.findOne({
|
||||||
|
where: {
|
||||||
|
regionId: regionId,
|
||||||
|
officeTypeId: { [Op.in]: higherOfficeTypeIds }
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'type',
|
||||||
|
attributes: ['hierarchyLevel']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: FalukantCharacter,
|
||||||
|
as: 'holder',
|
||||||
|
attributes: ['id']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [
|
||||||
|
[{ model: ChurchOfficeType, as: 'type' }, 'hierarchyLevel', 'ASC']
|
||||||
|
],
|
||||||
|
limit: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!supervisorOffice || !supervisorOffice.holder) {
|
||||||
|
throw new Error('No supervisor found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe ob bereits eine Bewerbung existiert
|
||||||
|
const existingApplication = await ChurchApplication.findOne({
|
||||||
|
where: {
|
||||||
|
characterId: character.id,
|
||||||
|
officeTypeId: officeTypeId,
|
||||||
|
regionId: regionId,
|
||||||
|
status: 'pending'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingApplication) {
|
||||||
|
throw new Error('Application already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erstelle Bewerbung
|
||||||
|
await ChurchApplication.create({
|
||||||
|
officeTypeId: officeTypeId,
|
||||||
|
characterId: character.id,
|
||||||
|
regionId: regionId,
|
||||||
|
supervisorId: supervisorOffice.holder.id,
|
||||||
|
status: 'pending'
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async decideOnChurchApplication(hashedUserId, applicationId, decision) {
|
||||||
|
const user = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const character = await FalukantCharacter.findOne({
|
||||||
|
where: { userId: user.id },
|
||||||
|
attributes: ['id']
|
||||||
|
});
|
||||||
|
if (!character) {
|
||||||
|
throw new Error('Character not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const application = await ChurchApplication.findOne({
|
||||||
|
where: {
|
||||||
|
id: applicationId,
|
||||||
|
supervisorId: character.id,
|
||||||
|
status: 'pending'
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ChurchOfficeType,
|
||||||
|
as: 'officeType',
|
||||||
|
attributes: ['id', 'seatsPerRegion']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!application) {
|
||||||
|
throw new Error('Application not found or not authorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decision === 'approve') {
|
||||||
|
// Prüfe ob noch Platz verfügbar ist
|
||||||
|
const occupiedCount = await ChurchOffice.count({
|
||||||
|
where: {
|
||||||
|
officeTypeId: application.officeTypeId,
|
||||||
|
regionId: application.regionId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (occupiedCount >= application.officeType.seatsPerRegion) {
|
||||||
|
throw new Error('No available seats');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erstelle Kirchenamt
|
||||||
|
await ChurchOffice.create({
|
||||||
|
officeTypeId: application.officeTypeId,
|
||||||
|
characterId: application.characterId,
|
||||||
|
regionId: application.regionId,
|
||||||
|
supervisorId: application.supervisorId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aktualisiere Bewerbung
|
||||||
|
application.status = decision === 'approve' ? 'approved' : 'rejected';
|
||||||
|
application.decisionDate = new Date();
|
||||||
|
await application.save();
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new FalukantService();
|
export default new FalukantService();
|
||||||
|
|||||||
@@ -307,6 +307,9 @@
|
|||||||
"current": "Laufende Produktionen",
|
"current": "Laufende Produktionen",
|
||||||
"product": "Produkt",
|
"product": "Produkt",
|
||||||
"remainingTime": "Verbleibende Zeit (Sekunden)",
|
"remainingTime": "Verbleibende Zeit (Sekunden)",
|
||||||
|
"status": "Status",
|
||||||
|
"sleep": "Pausiert",
|
||||||
|
"active": "Aktiv",
|
||||||
"noProductions": "Keine laufenden Produktionen."
|
"noProductions": "Keine laufenden Produktionen."
|
||||||
},
|
},
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|||||||
@@ -165,6 +165,29 @@
|
|||||||
"income": "Income",
|
"income": "Income",
|
||||||
"incomeUpdated": "Salary has been successfully updated."
|
"incomeUpdated": "Salary has been successfully updated."
|
||||||
},
|
},
|
||||||
|
"production": {
|
||||||
|
"title": "Production",
|
||||||
|
"info": "Details about production in the branch.",
|
||||||
|
"selectProduct": "Select product",
|
||||||
|
"quantity": "Quantity",
|
||||||
|
"storageAvailable": "Free storage",
|
||||||
|
"cost": "Cost",
|
||||||
|
"duration": "Duration",
|
||||||
|
"revenue": "Revenue",
|
||||||
|
"start": "Start production",
|
||||||
|
"success": "Production started successfully!",
|
||||||
|
"error": "Error starting production.",
|
||||||
|
"minutes": "Minutes",
|
||||||
|
"ending": "Ending:",
|
||||||
|
"time": "Time",
|
||||||
|
"current": "Running productions",
|
||||||
|
"product": "Product",
|
||||||
|
"remainingTime": "Remaining time (seconds)",
|
||||||
|
"status": "Status",
|
||||||
|
"sleep": "Paused",
|
||||||
|
"active": "Active",
|
||||||
|
"noProductions": "No running productions."
|
||||||
|
},
|
||||||
"vehicles": {
|
"vehicles": {
|
||||||
"cargo_cart": "Cargo cart",
|
"cargo_cart": "Cargo cart",
|
||||||
"ox_cart": "Ox cart",
|
"ox_cart": "Ox cart",
|
||||||
|
|||||||
Reference in New Issue
Block a user