'Producer',
'manufacturer' => 'Manufacturer',
'supplier' => 'Supplier',
'vendor' => 'Vendor',
'factory' => 'Factory',
'agent' => 'Agent',
'invoice_to' => 'Invoice To',
'report_to' => 'Report To',
'laboratory' => 'Laboratory',
'other' => 'Other',
];
$partnerStatuses = [
'active' => 'Active',
'inactive' => 'Inactive',
'suspended' => 'Suspended',
];
$contactStatuses = [
'active' => 'Active',
'inactive' => 'Inactive',
];
/*
* AJAX actions
*/
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
try {
if ($action === 'save_partner') {
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
$idcompany = isset($_POST['idcompany']) ? (int) $_POST['idcompany'] : 0;
$partnerType = $_POST['partner_type'] ?? 'supplier';
$partnerName = trim($_POST['partner_name'] ?? '');
$legalName = trim($_POST['legal_name'] ?? '');
$externalCode = trim($_POST['external_code'] ?? '');
$vatNumber = trim($_POST['vat_number'] ?? '');
$taxCode = trim($_POST['tax_code'] ?? '');
$address = trim($_POST['address'] ?? '');
$city = trim($_POST['city'] ?? '');
$zip = trim($_POST['zip'] ?? '');
$countryId = !empty($_POST['country_id']) ? (int) $_POST['country_id'] : null;
$email = trim($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$website = trim($_POST['website'] ?? '');
$notes = trim($_POST['notes'] ?? '');
$status = $_POST['status'] ?? 'active';
if ($idcompany <= 0) {
jsonResponse([
'success' => false,
'message' => 'Company is required.'
]);
}
if ($partnerName === '') {
jsonResponse([
'success' => false,
'message' => 'Partner name is required.'
]);
}
if (!array_key_exists($partnerType, $partnerTypes)) {
$partnerType = 'supplier';
}
if (!array_key_exists($status, $partnerStatuses)) {
$status = 'active';
}
/*
* Check company exists.
*/
$stmt = $db->prepare("
SELECT COUNT(*)
FROM companies
WHERE idcompany = :idcompany
");
$stmt->execute([':idcompany' => $idcompany]);
if ((int) $stmt->fetchColumn() === 0) {
jsonResponse([
'success' => false,
'message' => 'Selected company does not exist.'
]);
}
if ($idpartner > 0) {
$sql = "
UPDATE business_partners
SET
idcompany = :idcompany,
partner_type = :partner_type,
partner_name = :partner_name,
legal_name = :legal_name,
external_code = :external_code,
vat_number = :vat_number,
tax_code = :tax_code,
address = :address,
city = :city,
zip = :zip,
country_id = :country_id,
email = :email,
phone = :phone,
website = :website,
notes = :notes,
status = :status,
updated_at = NOW()
WHERE idpartner = :idpartner
";
$stmt = $db->prepare($sql);
$stmt->execute([
':idcompany' => $idcompany,
':partner_type' => $partnerType,
':partner_name' => $partnerName,
':legal_name' => $legalName !== '' ? $legalName : null,
':external_code' => $externalCode !== '' ? $externalCode : null,
':vat_number' => $vatNumber !== '' ? $vatNumber : null,
':tax_code' => $taxCode !== '' ? $taxCode : null,
':address' => $address !== '' ? $address : null,
':city' => $city !== '' ? $city : null,
':zip' => $zip !== '' ? $zip : null,
':country_id' => $countryId,
':email' => $email !== '' ? $email : null,
':phone' => $phone !== '' ? $phone : null,
':website' => $website !== '' ? $website : null,
':notes' => $notes !== '' ? $notes : null,
':status' => $status,
':idpartner' => $idpartner,
]);
jsonResponse([
'success' => true,
'message' => 'Business partner updated successfully.'
]);
}
$sql = "
INSERT INTO business_partners (
idcompany,
partner_type,
partner_name,
legal_name,
external_code,
vat_number,
tax_code,
address,
city,
zip,
country_id,
email,
phone,
website,
notes,
status,
created_by,
created_at,
updated_at
) VALUES (
:idcompany,
:partner_type,
:partner_name,
:legal_name,
:external_code,
:vat_number,
:tax_code,
:address,
:city,
:zip,
:country_id,
:email,
:phone,
:website,
:notes,
:status,
:created_by,
NOW(),
NOW()
)
";
$stmt = $db->prepare($sql);
$stmt->execute([
':idcompany' => $idcompany,
':partner_type' => $partnerType,
':partner_name' => $partnerName,
':legal_name' => $legalName !== '' ? $legalName : null,
':external_code' => $externalCode !== '' ? $externalCode : null,
':vat_number' => $vatNumber !== '' ? $vatNumber : null,
':tax_code' => $taxCode !== '' ? $taxCode : null,
':address' => $address !== '' ? $address : null,
':city' => $city !== '' ? $city : null,
':zip' => $zip !== '' ? $zip : null,
':country_id' => $countryId,
':email' => $email !== '' ? $email : null,
':phone' => $phone !== '' ? $phone : null,
':website' => $website !== '' ? $website : null,
':notes' => $notes !== '' ? $notes : null,
':status' => $status,
':created_by' => $iduserlogin,
]);
jsonResponse([
'success' => true,
'message' => 'Business partner created successfully.'
]);
}
if ($action === 'get_partner') {
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
if ($idpartner <= 0) {
jsonResponse([
'success' => false,
'message' => 'Invalid partner id.'
]);
}
$stmt = $db->prepare("
SELECT *
FROM business_partners
WHERE idpartner = :idpartner
LIMIT 1
");
$stmt->execute([':idpartner' => $idpartner]);
$partner = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$partner) {
jsonResponse([
'success' => false,
'message' => 'Business partner not found.'
]);
}
jsonResponse([
'success' => true,
'partner' => $partner
]);
}
if ($action === 'change_partner_status') {
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
$status = $_POST['status'] ?? 'inactive';
if ($idpartner <= 0 || !array_key_exists($status, $partnerStatuses)) {
jsonResponse([
'success' => false,
'message' => 'Invalid request.'
]);
}
$stmt = $db->prepare("
UPDATE business_partners
SET status = :status, updated_at = NOW()
WHERE idpartner = :idpartner
");
$stmt->execute([
':status' => $status,
':idpartner' => $idpartner,
]);
jsonResponse([
'success' => true,
'message' => 'Business partner status updated successfully.'
]);
}
if ($action === 'delete_partner') {
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
if ($idpartner <= 0) {
jsonResponse([
'success' => false,
'message' => 'Invalid partner id.'
]);
}
/*
* Safe delete:
* Do not delete a partner if already used by samples or parts.
*/
$stmt = $db->prepare("
SELECT
(SELECT COUNT(*) FROM samples WHERE idproducer = :idpartner1 OR idsupplier = :idpartner2) AS samples_count,
(SELECT COUNT(*) FROM sample_parts WHERE supplier_id = :idpartner3 OR producer_id = :idpartner4) AS parts_count
");
$stmt->execute([
':idpartner1' => $idpartner,
':idpartner2' => $idpartner,
':idpartner3' => $idpartner,
':idpartner4' => $idpartner,
]);
$usage = $stmt->fetch(PDO::FETCH_ASSOC);
if (((int) $usage['samples_count'] > 0) || ((int) $usage['parts_count'] > 0)) {
jsonResponse([
'success' => false,
'message' => 'This partner is linked to samples or BOM parts. Set it as inactive instead of deleting it.'
]);
}
$stmt = $db->prepare("
DELETE FROM business_partners
WHERE idpartner = :idpartner
");
$stmt->execute([':idpartner' => $idpartner]);
jsonResponse([
'success' => true,
'message' => 'Business partner deleted successfully.'
]);
}
if ($action === 'get_partner_contacts') {
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
if ($idpartner <= 0) {
jsonResponse([
'success' => false,
'message' => 'Invalid partner id.'
]);
}
$stmt = $db->prepare("
SELECT *
FROM business_partner_contacts
WHERE idpartner = :idpartner
ORDER BY is_primary DESC, contact_name ASC
");
$stmt->execute([':idpartner' => $idpartner]);
jsonResponse([
'success' => true,
'contacts' => $stmt->fetchAll(PDO::FETCH_ASSOC)
]);
}
if ($action === 'save_contact') {
$idcontact = isset($_POST['idcontact']) ? (int) $_POST['idcontact'] : 0;
$idpartner = isset($_POST['idpartner']) ? (int) $_POST['idpartner'] : 0;
$contactName = trim($_POST['contact_name'] ?? '');
$role = trim($_POST['role'] ?? '');
$email = trim($_POST['email'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$mobile = trim($_POST['mobile'] ?? '');
$isPrimary = isset($_POST['is_primary']) ? (int) $_POST['is_primary'] : 0;
$notes = trim($_POST['notes'] ?? '');
$status = $_POST['status'] ?? 'active';
if ($idpartner <= 0) {
jsonResponse([
'success' => false,
'message' => 'Partner is required.'
]);
}
if ($contactName === '') {
jsonResponse([
'success' => false,
'message' => 'Contact name is required.'
]);
}
if (!array_key_exists($status, $contactStatuses)) {
$status = 'active';
}
/*
* If this contact is primary, unset other primary contacts for the same partner.
*/
if ($isPrimary === 1) {
$stmt = $db->prepare("
UPDATE business_partner_contacts
SET is_primary = 0
WHERE idpartner = :idpartner
");
$stmt->execute([':idpartner' => $idpartner]);
}
if ($idcontact > 0) {
$stmt = $db->prepare("
UPDATE business_partner_contacts
SET
contact_name = :contact_name,
role = :role,
email = :email,
phone = :phone,
mobile = :mobile,
is_primary = :is_primary,
notes = :notes,
status = :status,
updated_at = NOW()
WHERE idcontact = :idcontact
AND idpartner = :idpartner
");
$stmt->execute([
':contact_name' => $contactName,
':role' => $role !== '' ? $role : null,
':email' => $email !== '' ? $email : null,
':phone' => $phone !== '' ? $phone : null,
':mobile' => $mobile !== '' ? $mobile : null,
':is_primary' => $isPrimary === 1 ? 1 : 0,
':notes' => $notes !== '' ? $notes : null,
':status' => $status,
':idcontact' => $idcontact,
':idpartner' => $idpartner,
]);
jsonResponse([
'success' => true,
'message' => 'Contact updated successfully.'
]);
}
$stmt = $db->prepare("
INSERT INTO business_partner_contacts (
idpartner,
contact_name,
role,
email,
phone,
mobile,
is_primary,
notes,
status,
created_at,
updated_at
) VALUES (
:idpartner,
:contact_name,
:role,
:email,
:phone,
:mobile,
:is_primary,
:notes,
:status,
NOW(),
NOW()
)
");
$stmt->execute([
':idpartner' => $idpartner,
':contact_name' => $contactName,
':role' => $role !== '' ? $role : null,
':email' => $email !== '' ? $email : null,
':phone' => $phone !== '' ? $phone : null,
':mobile' => $mobile !== '' ? $mobile : null,
':is_primary' => $isPrimary === 1 ? 1 : 0,
':notes' => $notes !== '' ? $notes : null,
':status' => $status,
]);
jsonResponse([
'success' => true,
'message' => 'Contact created successfully.'
]);
}
if ($action === 'get_contact') {
$idcontact = isset($_POST['idcontact']) ? (int) $_POST['idcontact'] : 0;
if ($idcontact <= 0) {
jsonResponse([
'success' => false,
'message' => 'Invalid contact id.'
]);
}
$stmt = $db->prepare("
SELECT *
FROM business_partner_contacts
WHERE idcontact = :idcontact
LIMIT 1
");
$stmt->execute([':idcontact' => $idcontact]);
$contact = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$contact) {
jsonResponse([
'success' => false,
'message' => 'Contact not found.'
]);
}
jsonResponse([
'success' => true,
'contact' => $contact
]);
}
if ($action === 'delete_contact') {
$idcontact = isset($_POST['idcontact']) ? (int) $_POST['idcontact'] : 0;
if ($idcontact <= 0) {
jsonResponse([
'success' => false,
'message' => 'Invalid contact id.'
]);
}
$stmt = $db->prepare("
DELETE FROM business_partner_contacts
WHERE idcontact = :idcontact
");
$stmt->execute([':idcontact' => $idcontact]);
jsonResponse([
'success' => true,
'message' => 'Contact deleted successfully.'
]);
}
jsonResponse([
'success' => false,
'message' => 'Unknown action.'
]);
} catch (Throwable $e) {
jsonResponse([
'success' => false,
'message' => $e->getMessage()
]);
}
}
/*
* Page data.
*/
$companies = [];
$countries = [];
$partners = [];
try {
$stmt = $db->query("
SELECT idcompany, company_name, status
FROM companies
ORDER BY company_name ASC
");
$companies = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
$companies = [];
}
try {
$stmt = $db->query("
SELECT id, name, iso_3166_2
FROM auth_countries
ORDER BY name ASC
");
$countries = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
$countries = [];
}
try {
$stmt = $db->query("
SELECT
bp.idpartner,
bp.idcompany,
bp.partner_type,
bp.partner_name,
bp.legal_name,
bp.external_code,
bp.vat_number,
bp.city,
bp.email,
bp.phone,
bp.status,
bp.created_at,
c.company_name,
ac.name AS country_name,
COUNT(DISTINCT bpc.idcontact) AS contacts_count,
SUM(CASE WHEN bpc.is_primary = 1 THEN 1 ELSE 0 END) AS primary_contacts_count,
COUNT(DISTINCT s1.idsample) AS producer_samples_count,
COUNT(DISTINCT s2.idsample) AS supplier_samples_count,
COUNT(DISTINCT sp1.idpart) AS producer_parts_count,
COUNT(DISTINCT sp2.idpart) AS supplier_parts_count
FROM business_partners bp
INNER JOIN companies c ON c.idcompany = bp.idcompany
LEFT JOIN auth_countries ac ON ac.id = bp.country_id
LEFT JOIN business_partner_contacts bpc ON bpc.idpartner = bp.idpartner
LEFT JOIN samples s1 ON s1.idproducer = bp.idpartner
LEFT JOIN samples s2 ON s2.idsupplier = bp.idpartner
LEFT JOIN sample_parts sp1 ON sp1.producer_id = bp.idpartner
LEFT JOIN sample_parts sp2 ON sp2.supplier_id = bp.idpartner
GROUP BY
bp.idpartner,
bp.idcompany,
bp.partner_type,
bp.partner_name,
bp.legal_name,
bp.external_code,
bp.vat_number,
bp.city,
bp.email,
bp.phone,
bp.status,
bp.created_at,
c.company_name,
ac.name
ORDER BY c.company_name ASC, bp.partner_name ASC
");
$partners = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
$partners = [];
}
$pageTitle = 'Business Partners';
$totalPartners = count($partners);
$activePartners = count(array_filter($partners, fn($row) => $row['status'] === 'active'));
$totalContacts = array_sum(array_map(fn($row) => (int) $row['contacts_count'], $partners));
?>
= e($pageTitle); ?> - = isset($titlewebsite) ? e($titlewebsite) : 'TRFgo'; ?>
TRFgo Master Data
Business Partners
Manage producers, suppliers, manufacturers, vendors, factories, laboratories and contacts.
These records will be used in sample identity cards, BOM parts, TRF requests and document flows.
Add Partner
Total Partners
= e($totalPartners); ?>
Active Partners
= e($activePartners); ?>
Contacts
= e($totalContacts); ?>
No companies available.
Create at least one company before adding business partners.
Partner
Company
Type
External Code
Country / City
Email
Contacts
Usage
Status
Actions
= e($partner['partner_name']); ?>
= e($partner['legal_name']); ?>
VAT: = e($partner['vat_number']); ?>
= e($partner['company_name']); ?>
= e($partnerTypeLabel); ?>
= !empty($partner['external_code']) ? e($partner['external_code']) : '- '; ?>
= !empty($partner['country_name']) ? e($partner['country_name']) : '- '; ?>
= e($partner['city']); ?>
= e($partner['email']); ?>
-
= e($partner['phone']); ?>
= e($partner['contacts_count']); ?>
= e($usageCount); ?>
Active
Suspended
Inactive