186 lines
8.3 KiB
PHP
186 lines
8.3 KiB
PHP
<?php
|
|
/**
|
|
* Generate document from template: merge placeholders, optional PDF conversion, download or save to Documents.
|
|
*/
|
|
|
|
class OnlyOfficeTemplates_CreateFromTemplate_Action extends Vtiger_Action_Controller
|
|
{
|
|
public function checkPermission(Vtiger_Request $request)
|
|
{
|
|
$record = $request->get('record');
|
|
$module = $request->get('source_module') ?: getSalesEntityType($record);
|
|
if (!isPermitted($module, 'DetailView', $record)) {
|
|
throw new AppException('LBL_PERMISSION_DENIED');
|
|
}
|
|
}
|
|
|
|
public function process(Vtiger_Request $request)
|
|
{
|
|
$recordId = (int)$request->get('record');
|
|
$templateId = (int)$request->get('template_id');
|
|
$format = strtolower($request->get('format') ?: 'pdf'); // pdf | docx
|
|
$mode = strtolower($request->get('mode') ?: 'download'); // download | save_to_documents
|
|
$module = $request->get('source_module') ?: getSalesEntityType($recordId);
|
|
|
|
if (!$recordId || !$templateId) {
|
|
echo json_encode(['success' => false, 'error' => 'Missing record or template_id']);
|
|
return;
|
|
}
|
|
|
|
require_once dirname(__DIR__) . '/models/OnlyOfficeTemplates_Model.php';
|
|
require_once dirname(__DIR__) . '/resources/S3Helper.php';
|
|
require_once dirname(__DIR__) . '/resources/MergeService.php';
|
|
require_once dirname(__DIR__) . '/resources/ConvertService.php';
|
|
|
|
$model = new OnlyOfficeTemplates_Model();
|
|
$template = $model->getTemplateById($templateId);
|
|
if (!$template) {
|
|
echo json_encode(['success' => false, 'error' => 'Template not found or access denied']);
|
|
return;
|
|
}
|
|
$config = $model->getConfig();
|
|
$s3 = new OnlyOfficeTemplates_S3Helper($config);
|
|
$mergeService = new OnlyOfficeTemplates_MergeService($s3, $config);
|
|
$convertService = new OnlyOfficeTemplates_ConvertService($config);
|
|
|
|
$placeholders = $mergeService->buildPlaceholders($module, $recordId);
|
|
$tempDir = null;
|
|
$docxPath = null;
|
|
$pdfPath = null;
|
|
|
|
try {
|
|
$docxPath = $mergeService->mergeToFile($template['s3_key'], $placeholders);
|
|
$tempDir = dirname($docxPath);
|
|
$baseName = pathinfo($template['file_name'], PATHINFO_FILENAME);
|
|
$outExt = ($format === 'pdf') ? 'pdf' : 'docx';
|
|
$outFileName = $baseName . '_' . $recordId . '.' . $outExt;
|
|
|
|
if ($format === 'pdf') {
|
|
$docxUrl = $this->putMergedDocxForConversion($s3, $config, $docxPath, $recordId, $templateId);
|
|
if (!$docxUrl) {
|
|
echo json_encode(['success' => false, 'error' => 'Could not expose DOCX URL for conversion']);
|
|
return;
|
|
}
|
|
$result = $convertService->convertToPdf($docxUrl, $template['file_name']);
|
|
if (!$result['success']) {
|
|
echo json_encode(['success' => false, 'error' => $result['error']]);
|
|
return;
|
|
}
|
|
$pdfPath = $result['pdfPath'];
|
|
}
|
|
|
|
if ($mode === 'save_to_documents') {
|
|
$fileToSave = ($format === 'pdf') ? $pdfPath : $docxPath;
|
|
$docId = $this->saveToDocuments($request, $module, $recordId, $fileToSave, $outFileName, $config);
|
|
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
|
|
echo json_encode(['success' => true, 'document_id' => $docId, 'message' => 'Saved to Documents']);
|
|
return;
|
|
}
|
|
|
|
$downloadPath = ($format === 'pdf') ? $pdfPath : $docxPath;
|
|
$mime = ($format === 'pdf') ? 'application/pdf' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
header('Content-Type: ' . $mime);
|
|
header('Content-Disposition: attachment; filename="' . basename($outFileName) . '"');
|
|
header('Content-Length: ' . filesize($downloadPath));
|
|
readfile($downloadPath);
|
|
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
|
|
} catch (Exception $e) {
|
|
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
|
|
if ($request->get('ajax')) {
|
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
} else {
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Upload merged DOCX to S3 temp and return public URL for OnlyOffice converter.
|
|
*/
|
|
private function putMergedDocxForConversion(OnlyOfficeTemplates_S3Helper $s3, array $config, $localPath, $recordId, $templateId)
|
|
{
|
|
$key = $s3->getTempKey($recordId, $templateId, 'docx');
|
|
$s3->uploadFile($localPath, $key, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
|
|
$bucket = $s3->getBucket();
|
|
$endpoint = $config['s3']['endpoint'] ?? '';
|
|
$base = preg_replace('#^https?://#', 'https://', $endpoint);
|
|
if (empty($base)) {
|
|
$base = 'https://s3.twcstorage.ru';
|
|
}
|
|
return rtrim($base, '/') . '/' . $bucket . '/' . $key;
|
|
}
|
|
|
|
/**
|
|
* Save file as Document record and link to parent. Use Documents S3 structure if FilePathManager available.
|
|
*/
|
|
private function saveToDocuments(Vtiger_Request $request, $module, $recordId, $localPath, $fileName, array $config)
|
|
{
|
|
$adb = PearDatabase::getInstance();
|
|
$currentUser = Users_Record_Model::getCurrentUserModel();
|
|
$ownerId = $currentUser->getId();
|
|
$docPrefix = $config['documents_s3_prefix'] ?? 'crm2/CRM_Active_Files/Documents';
|
|
$bucket = $config['s3_bucket'] ?? $config['s3']['bucket'];
|
|
|
|
$notesId = $adb->getUniqueID('vtiger_crmentity');
|
|
if (!$notesId) {
|
|
$r = $adb->pquery("SELECT MAX(crmid) AS m FROM vtiger_crmentity", []);
|
|
$notesId = (int)$adb->query_result($r, 0, 'm') + 1;
|
|
}
|
|
|
|
$title = pathinfo($fileName, PATHINFO_FILENAME);
|
|
$now = date('Y-m-d H:i:s');
|
|
$s3Key = $docPrefix . '/' . $module . '/' . $module . '_' . $recordId . '/' . $title . '_' . $notesId . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
|
|
|
|
$s3 = new OnlyOfficeTemplates_S3Helper($config);
|
|
$contentType = (pathinfo($fileName, PATHINFO_EXTENSION) === 'pdf') ? 'application/pdf' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
$s3->uploadFile($localPath, $s3Key, $contentType);
|
|
|
|
$fileUrl = 'https://' . ($config['s3']['endpoint'] ?? 's3.twcstorage.ru');
|
|
$fileUrl = preg_replace('#^https?://#', '', $fileUrl);
|
|
$fileUrl = 'https://' . $fileUrl . '/' . $bucket . '/' . $s3Key;
|
|
$fileSize = filesize($localPath);
|
|
|
|
$adb->pquery(
|
|
"INSERT INTO vtiger_crmentity (crmid, smownerid, smcreatorid, modifiedby, setype, description, createdtime, modifiedtime, presence, deleted) VALUES (?,?,?,?,?,?,?,?,?,?)",
|
|
[$notesId, $ownerId, $ownerId, $ownerId, 'Documents', '', $now, $now, 1, 0]
|
|
);
|
|
$adb->pquery(
|
|
"INSERT INTO vtiger_notes (notesid, title, filename, filesize, filetype, filelocationtype, filedownloadcount, createdtime, modifiedtime, folderid, notecontent) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
|
[$notesId, $title, $fileUrl, $fileSize, $contentType, 'E', 0, $now, $now, 0, '']
|
|
);
|
|
if (method_exists($adb, 'pquery')) {
|
|
$adb->pquery("INSERT INTO vtiger_senotesrel (crmid, notesid) VALUES (?,?)", [$recordId, $notesId]);
|
|
}
|
|
$adb->pquery("INSERT INTO vtiger_notescf (notesid) VALUES (?)", [$notesId]);
|
|
|
|
if ($this->hasS3Columns($adb)) {
|
|
$adb->pquery("UPDATE vtiger_notes SET s3_bucket = ?, s3_key = ? WHERE notesid = ?", [$bucket, $s3Key, $notesId]);
|
|
}
|
|
|
|
return $notesId;
|
|
}
|
|
|
|
private function hasS3Columns($adb)
|
|
{
|
|
static $has = null;
|
|
if ($has === null) {
|
|
$r = @$adb->pquery("SHOW COLUMNS FROM vtiger_notes LIKE 's3_key'", []);
|
|
$has = $r && $adb->num_rows($r) > 0;
|
|
}
|
|
return $has;
|
|
}
|
|
|
|
private function cleanupTemp($tempDir, $docxPath, $pdfPath)
|
|
{
|
|
if ($pdfPath && is_file($pdfPath)) {
|
|
@unlink($pdfPath);
|
|
}
|
|
if ($docxPath && is_file($docxPath)) {
|
|
@unlink($docxPath);
|
|
}
|
|
if ($tempDir && is_dir($tempDir)) {
|
|
@rmdir($tempDir);
|
|
}
|
|
}
|
|
}
|