Merge branch 'development' into feat/FE/US-335/production-data-report

This commit is contained in:
ValdiANS
2025-12-18 18:50:22 +07:00
parent 65b60cc464
commit 096a8d394e
112 changed files with 7158 additions and 3238 deletions
+151 -6
View File
@@ -6,19 +6,85 @@ import {
ClosingGeneralInformation,
ClosingIncomingSapronak,
ClosingOutgoingSapronak,
ClosingOverhead,
ClosingSapronakCalculation,
ClosingProductionData,
} from '@/types/api/closing';
import { httpClient, httpClientFetcher } from '@/services/http/client';
import { BaseApiResponse } from '@/types/api/api-general';
import {
dummyGetAllFetcher,
dummyGetSingle,
dummyGetAllIncomingSapronakFetcher,
dummyGetAllOutgoingSapronakFetcher,
dummyGetGeneralInfo,
dummyGetPerhitunganSapronak,
dummyGetOverhead,
} from '@/dummy/closing.dummy';
import { httpClient, httpClientFetcher } from '@/services/http/client';
import { ClosingSales } from '@/types/api/closing';
export class ClosingApiService extends BaseApiService<Closing, null, null> {
constructor(basePath: string) {
super(basePath);
}
async getAllFetcher(endpoint: string): Promise<BaseApiResponse<Closing[]>> {
// TODO: Remove this block when backend is ready
// return await dummyGetAllFetcher();
// Uncomment this when backend is ready
return await httpClientFetcher<BaseApiResponse<Closing[]>>(endpoint);
}
async getSingle(id: number): Promise<BaseApiResponse<Closing> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetSingle(id);
// } catch (error) {
// if (axios.isAxiosError<BaseApiResponse<Closing>>(error)) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try {
const getSinglePath = `${this.basePath}/${id}`;
const getSingleRes =
await httpClient<BaseApiResponse<Closing>>(getSinglePath);
return getSingleRes;
} catch (error) {
if (axios.isAxiosError<BaseApiResponse<Closing>>(error)) {
return error.response?.data;
}
return undefined;
}
}
async getPenjualan(
id: number
): Promise<BaseApiResponse<ClosingSales> | undefined> {
try {
const getPenjualanPath = `${this.basePath}/${id}/penjualan`;
const getPenjualanRes =
await httpClient<BaseApiResponse<ClosingSales>>(getPenjualanPath);
return getPenjualanRes;
} catch (error) {
if (axios.isAxiosError<BaseApiResponse<ClosingSales>>(error)) {
return error.response?.data;
}
return undefined;
}
}
async getAllIncomingSapronakFetcher(
endpoint: string
): Promise<BaseApiResponse<ClosingIncomingSapronak[]>> {
// TODO: Remove this block when backend is ready
// return await dummyGetAllIncomingSapronakFetcher();
// Uncomment this when backend is ready
return await httpClientFetcher<BaseApiResponse<ClosingIncomingSapronak[]>>(
endpoint
);
@@ -27,19 +93,37 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
async getAllOutgoingSapronakFetcher(
endpoint: string
): Promise<BaseApiResponse<ClosingOutgoingSapronak[]>> {
return await httpClientFetcher<BaseApiResponse<ClosingOutgoingSapronak[]>>(
endpoint
);
// TODO: Remove this block when backend is ready
return await dummyGetAllOutgoingSapronakFetcher();
// Uncomment this when backend is ready
// return await httpClientFetcher<BaseApiResponse<ClosingOutgoingSapronak[]>>(
// endpoint
// );
}
async getGeneralInfo(id: number) {
async getGeneralInfo(
id: number
): Promise<BaseApiResponse<ClosingGeneralInformation> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetGeneralInfo(id);
// } catch (error) {
// if (
// axios.isAxiosError<BaseApiResponse<ClosingGeneralInformation>>(error)
// ) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try {
const getGeneralInfoPath = `${this.basePath}/${id}`;
const getGeneralInfoRes =
await httpClient<BaseApiResponse<ClosingGeneralInformation>>(
getGeneralInfoPath
);
return getGeneralInfoRes;
} catch (error) {
if (
@@ -66,6 +150,67 @@ export class ClosingApiService extends BaseApiService<Closing, null, null> {
return undefined;
}
}
async getPerhitunganSapronak(
id: number
): Promise<BaseApiResponse<ClosingSapronakCalculation> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetPerhitunganSapronak(id);
// } catch (error) {
// if (
// axios.isAxiosError<BaseApiResponse<ClosingSapronakCalculation>>(error)
// ) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try {
const path = `${this.basePath}/${id}/perhitungan_sapronak`;
return await httpClient<BaseApiResponse<ClosingSapronakCalculation>>(
path,
{
method: 'GET',
}
);
} catch (error) {
if (
axios.isAxiosError<BaseApiResponse<ClosingSapronakCalculation>>(error)
) {
return error.response?.data;
}
return undefined;
}
}
async getOverhead(
id: number
): Promise<BaseApiResponse<ClosingOverhead> | undefined> {
// TODO: Remove this block when backend is ready
// try {
// return await dummyGetOverhead(id);
// } catch (error) {
// if (axios.isAxiosError<BaseApiResponse<ClosingOverhead>>(error)) {
// return error.response?.data;
// }
// return undefined;
// }
// Uncomment this when backend is ready
try {
const path = `${this.basePath}/${id}/overhead`;
return await httpClient<BaseApiResponse<ClosingOverhead>>(path, {
method: 'GET',
});
} catch (error) {
if (axios.isAxiosError<BaseApiResponse<ClosingOverhead>>(error)) {
return error.response?.data;
}
return undefined;
}
}
}
export const ClosingApi = new ClosingApiService('/closings');
+4 -4
View File
@@ -492,8 +492,8 @@ export class ExpenseApiService extends BaseApiService<
});
formData.append(
'cost_per_kandangs',
JSON.stringify(payload.cost_per_kandangs)
'expense_nonstocks',
JSON.stringify(payload.expense_nonstocks)
);
return formData;
@@ -514,8 +514,8 @@ export class ExpenseApiService extends BaseApiService<
});
formData.append(
'cost_per_kandang',
JSON.stringify(payload.cost_per_kandang)
'expense_nonstocks',
JSON.stringify(payload.expense_nonstocks)
);
return formData;
+8 -1
View File
@@ -12,6 +12,7 @@ import {
CreateInventoryAdjustmentPayload,
InventoryAdjustment,
} from '@/types/api/inventory/adjustment';
import { InventoryProduct } from '@/types/api/inventory/product';
export const ProductWarehouseApi = new BaseApiService<
ProductWarehouse,
@@ -25,8 +26,14 @@ export const MovementApi = new BaseApiService<
unknown
>('/inventory/transfers');
export const inventoryAdjustmentApi = new BaseApiService<
export const InventoryAdjustmentApi = new BaseApiService<
InventoryAdjustment,
CreateInventoryAdjustmentPayload,
unknown
>('/inventory/adjustments');
export const InventoryProductApi = new BaseApiService<
InventoryProduct,
unknown,
unknown
>('/inventory/product-stocks');
+1 -25
View File
@@ -1,4 +1,4 @@
import { BaseApiService } from './base';
import { BaseApiService } from '@/services/api/base';
import { BaseApiResponse } from '@/types/api/api-general';
import {
CreateProjectFlockPayload,
@@ -9,8 +9,6 @@ import {
CreateRecordingPayload,
Recording,
UpdateRecordingPayload,
CreateGradingPayload,
UpdateGradingPayload,
NextDayRecording,
} from '@/types/api/production/recording';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
@@ -64,28 +62,6 @@ export class RecordingService extends BaseApiService<
});
}
async createGrading(
payload: CreateGradingPayload
): Promise<BaseApiResponse<unknown> | undefined> {
return await this.customRequest<BaseApiResponse<unknown>>('gradings', {
method: 'POST',
payload,
});
}
async updateGrading(
gradingId: number,
payload: UpdateGradingPayload
): Promise<BaseApiResponse<unknown> | undefined> {
return await this.customRequest<BaseApiResponse<unknown>>(
`gradings/${gradingId}`,
{
method: 'PUT',
payload,
}
);
}
async deleteGrading(
gradingId: number
): Promise<BaseApiResponse<unknown> | undefined> {
@@ -2,10 +2,187 @@ import { BaseApiService } from '@/services/api/base';
import {
BaseProjectFlockKandang,
ProjectFlockKandang,
ClosingProjectFlockKandangPayload,
CheckClosingResponse,
} from '@/types/api/production/project-flock-kandang';
import { BaseApiResponse } from '@/types/api/api-general';
import { httpClient } from '@/services/http/client';
import axios from 'axios';
export const ProjectFlockKandangApi = new BaseApiService<
export class ProjectFlockKandangService extends BaseApiService<
BaseProjectFlockKandang,
ProjectFlockKandang,
unknown
>('project-flock-kandang');
> {
constructor(basePath: string = '') {
super(basePath);
}
/**
* Close or Unclose Project Flock Kandang
*/
async closing(
id: number,
payload: ClosingProjectFlockKandangPayload
): Promise<BaseApiResponse<{ message: string }> | undefined> {
try {
const path = `${this.basePath}/${id}/closing`;
const headers = {
'Content-Type': 'application/json',
...(this.header ?? {}),
};
return await httpClient<BaseApiResponse<{ message: string }>>(path, {
method: 'POST',
body: payload,
headers,
});
} catch (error: unknown) {
if (axios.isAxiosError<BaseApiResponse<{ message: string }>>(error)) {
return error.response?.data;
}
return undefined;
}
}
/**
* Check Closing Requirements for Project Flock Kandang
* TODO: Replace with actual API call when backend is ready
*/
async checkClosing(
id: number
): Promise<BaseApiResponse<CheckClosingResponse> | undefined> {
// Dummy data - replace with actual API call when backend is ready
// return new Promise((resolve) => {
// setTimeout(() => {
// resolve({
// code: 200,
// status: 'success',
// message: 'Cek persyaratan closing kandang',
// data: {
// unfinished_expenses: id % 2 === 1 ? 2 : 0,
// stock_remaining: [
// {
// id: 1,
// product_id: 1,
// warehouse_id: 1,
// quantity: id % 2 === 1 ? 100 : 0,
// product: {
// id: 1,
// name: 'Pakan Starter',
// brand: 'Brand A',
// sku: 'PKN-STR-001',
// product_price: 15000,
// selling_price: 17000,
// tax: 0,
// expiry_period: 365,
// flags: ['active'],
// uom: {
// id: 1,
// name: 'Kg',
// created_user: {
// id: 1,
// id_user: 1,
// email: 'admin@example.com',
// name: 'Admin User',
// },
// created_at: '2024-01-01',
// updated_at: '2024-01-01',
// },
// product_category: {
// id: 1,
// name: 'Pakan',
// code: 'PKN',
// created_user: {
// id: 1,
// id_user: 1,
// email: 'admin@example.com',
// name: 'Admin User',
// },
// created_at: '2024-01-01',
// updated_at: '2024-01-01',
// },
// suppliers: [],
// created_user: {
// id: 1,
// id_user: 1,
// email: 'admin@example.com',
// name: 'Admin User',
// },
// created_at: '2024-01-01',
// updated_at: '2024-01-01',
// },
// warehouse: {
// id: 1,
// name: 'Gudang Utama',
// type: 'AREA',
// area: {
// id: 1,
// name: 'Area 1',
// },
// created_user: {
// id: 1,
// id_user: 1,
// email: 'admin@example.com',
// name: 'Admin User',
// },
// created_at: '2024-01-01',
// updated_at: '2024-01-01',
// },
// created_user: {
// id: 1,
// id_user: 1,
// email: 'admin@example.com',
// name: 'Admin User',
// },
// created_at: '2025-01-01',
// updated_at: '2025-01-01',
// },
// ],
// expenses: [
// {
// id: 1,
// po_number: 'PO-BOP-LTI-00001',
// category: 'NON-BOP',
// total: 110000,
// status: id % 2 === 1 ? 'PENGAJUAN' : 'SELESAI',
// step_name: id % 2 === 1 ? 'Approval Finance' : 'Selesai',
// step: id % 2 === 1 ? 1 : 5,
// reference_number: 'BOP-LTI-00001',
// },
// {
// id: 3,
// po_number: 'PO-BOP-LTI-00003',
// category: 'BOP',
// total: 110000,
// status: id % 2 === 1 ? 'PENGAJUAN' : 'SELESAI',
// step_name: id % 2 === 1 ? 'Approval Finance' : 'Selesai',
// step: id % 2 === 1 ? 1 : 5,
// reference_number: 'BOP-LTI-00003',
// },
// ],
// },
// });
// }, 500); // Simulate network delay
// });
// Original API call - uncomment when backend is ready
try {
const path = `${this.basePath}/${id}/closing/check`;
return await httpClient<BaseApiResponse<CheckClosingResponse>>(path, {
method: 'GET',
});
} catch (error: unknown) {
if (axios.isAxiosError<BaseApiResponse<CheckClosingResponse>>(error)) {
return error.response?.data;
}
return undefined;
}
}
}
export const ProjectFlockKandangApi = new ProjectFlockKandangService(
'/production/project-flock-kandangs'
);
@@ -141,6 +141,38 @@ export class ProjectFlockService extends BaseApiService<
}
}
/**
* Resubmit Project Flock
*/
async resubmit(
id: number,
payload: UpdateProjectFlockPayload
): Promise<BaseApiResponse<ProjectFlock> | undefined> {
try {
const updatePath = `${this.basePath}/${id}/resubmit`;
const headers = {
'Content-Type': 'application/json',
...(this.header ?? {}),
};
const updateRes = await httpClient<BaseApiResponse<ProjectFlock>>(
updatePath,
{
method: 'PUT',
body: payload,
headers,
}
);
return updateRes;
} catch (error: unknown) {
if (axios.isAxiosError<BaseApiResponse<ProjectFlock>>(error)) {
return error.response?.data;
}
return undefined;
}
}
/**
* Approve single Project Flock
*/