I'm looking to create an ''attachment'' field in a module. Same thing as the field ''File Name'' in the ''Documents'' module.
How can I do that?
Thanks
I'm looking to create an ''attachment'' field in a module. Same thing as the field ''File Name'' in the ''Documents'' module.
How can I do that?
Thanks
Hello Dave,
This was tested in Sugar 7.6.1.0 Professional:
1. Login as a System Administrator.
2. Navigate to Admin > Studio > {Sidecar Module such as Accounts} > Fields.
3. Click 'Add Field'.
4. Create a new TextField type field and add it to the Record View.
5. In the Sugar File System, locate the following file:
./custom/Extension/modules/{Module}/Ext/Vardefs/sugarfield_{Field Name}.php
6. Modify this file and add the following line, making the necessary adjustments:
$dictionary['Account']['fields']['{Field Name}']['type']='file';
7. Return to the Sugar application and navigate to Admin > Repair.
8. Select 'Quick Repair and Rebuild'.
When you create or edit a record in the module where you added the field, it will now display and behave as a File type field that allows you to upload attachments.
Regards,
Dan Kallish
Advanced Support Engineer
SUGARCRM
Learning Resources: http://support.sugarcrm.com | http://university.sugarcrm.com | http://community.sugarcrm.com
Hi Dan.
Thanks for a very thorough explanation. It´s all working until I try to open an already saved attachment in Sugar. The attachment does not keep it´s original name and extension. Instead, it gets a new name, like 315d4014-283d-a1a2-c1a1-572a839cf531, see pic:
Any idea how that can be fixed (apart from manual renaming)?
Lori Arce - do you know?
Thanks again,
KGM
Hi Dan Kallish
I have used the similar procedure and was able to upload the file in Tasks module.
But facing issue while deleting file
In console i have chekced and found this.
jquery.min.js:4 DELETE http://<url>/rest/v10/Tasks/50cfb408-0856-11e6-a18a-fa163e8c8e90/file/attachment_c?delete_if_fails=true&platform=base 404 (Not Found)
Can you please update me regarding this.
Regards
Sidhu
Hello Sindhu,
Hope this will helps.
Creating a File Upload Field for a Core Module/Custom Module in Sugar 7.x - Bhea Blog
Best Regards,
Vignesh V
Hi Sidhu,
Can you please tell me how did you solve this problem? I'm working in sugar 8.3.
I Have done Whatever have In Blog When Finally click on quick repair 1st step is excuted succesfully field created and uploading documents succesfully.But in 2nd step we need to add delete attachment function where i got a parse error and stopping excution.
Note:: Bold Text is the added code in original file
Parse error: syntax error, unexpected end of file, expecting function (T_FUNCTION) in D:\xampp1\htdocs\scrm\custom\modules\Cases\Case.php on line 359
and this is the page Case.php
<?php
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
// aCase is used to store case information.
require_once('include/upload_file.php');
class aCase extends Basic
{
var $field_name_map = array();
// Stored fields
var $id;
var $date_entered;
var $date_modified;
var $modified_user_id;
var $assigned_user_id;
var $team_id;
var $case_number;
var $resolution;
var $description;
var $name;
var $status;
var $priority;
var $created_by;
var $created_by_name;
var $modified_by_name;
// These are related
var $bug_id;
var $account_name;
var $account_id;
var $contact_id;
var $task_id;
var $note_id;
var $meeting_id;
var $call_id;
var $email_id;
var $assigned_user_name;
var $team_name;
var $system_id;
var $table_name = "cases";
var $rel_account_table = "accounts_cases";
var $rel_contact_table = "contacts_cases";
var $module_dir = 'Cases';
var $object_name = "Case";
var $importable = true;
/** "%1" is the case_number, for emails
* leave the %1 in if you customize this
* YOU MUST LEAVE THE BRACKETS AS WELL*/
var $emailSubjectMacro = '[CASE:%1]';
// This is used to retrieve related fields from form posts.
var $additional_column_fields = array(
'bug_id',
'assigned_user_name',
'assigned_user_id',
'contact_id',
'task_id',
'note_id',
'meeting_id',
'call_id',
'email_id'
);
var $relationship_fields = array(
'account_id'=>'accounts',
'bug_id' => 'bugs',
'task_id'=>'tasks',
'note_id'=>'notes',
'meeting_id'=>'meetings',
'call_id'=>'calls',
'email_id'=>'emails',
);
public function __construct()
{
parent::__construct();
global $sugar_config;
if (empty($sugar_config['require_accounts'])) {
unset($this->required_fields['account_name']);
}
$this->setupCustomFields('Cases');
foreach ($this->field_defs as $name => $field) {
$this->field_name_map[$name] = $field;
}
}
var $new_schema = true;
function get_summary_text()
{
return "$this->name";
}
function listviewACLHelper()
{
$array_assign = parent::listviewACLHelper();
$is_owner = false;
if (!empty($this->account_id)) {
if (!empty($this->account_id_owner)) {
global $current_user;
$is_owner = $current_user->id == $this->account_id_owner;
}
}
if (!ACLController::moduleSupportsACL('Accounts') ||
ACLController::checkAccess('Accounts', 'view', $is_owner)
) {
$array_assign['ACCOUNT'] = 'a';
} else {
$array_assign['ACCOUNT'] = 'span';
}
return $array_assign;
}
/**
* This function is a good location to save changes that have been made to a relationship.
* This should be overridden in subclasses that have something to save.
*
* @param boolean $is_update true if this save is an update.
* @param array $exclude a way to exclude relationships
*
* @see SugarBean::save_relationship_changes()
*/
public function save_relationship_changes($is_update, $exclude = array())
{
parent::save_relationship_changes($is_update);
if (!empty($this->contact_id)) {
$this->set_case_contact_relationship($this->contact_id);
}
}
function set_case_contact_relationship($contact_id)
{
global $app_list_strings;
$default = $app_list_strings['case_relationship_type_default_key'];
$this->load_relationship('contacts');
$this->contacts->add($contact_id, array('contact_role'=>$default));
}
function fill_in_additional_detail_fields()
{
parent::fill_in_additional_detail_fields();
if (!empty($this->id)) {
$account_info = $this->getAccount($this->id);
if (!empty($account_info)) {
$this->account_name = $account_info['account_name'];
$this->account_id = $account_info['account_id'];
}
}
}
function deleteAttachment($isduplicate="false"){
if($this->ACLAccess('edit')){
if($isduplicate=="true"){
return true;
}
$removeFile = "upload://{$this->id}";
}
if(SugarAutoloader::fileExists($removeFile)) {
if(!UploadFile::unlink($removeFile)) {
$GLOBALS['log']->error("*** Could not unlink() file: [ {$removeFile} ]");
}else{
$this->filename = ";
$this->file_mime_type = ";
$this->file = ";
$this->save();
return true;
}
}else{
$this->filename = ";
$this->file_mime_type = ";
$this->file = ";
$this->save();
return true;
}
return false;
}
/**
* Returns a list of the associated contacts
*/
function get_contacts()
{
$this->load_relationship('contacts');
$query_array=$this->contacts->getQuery(true);
// update the select clause in the returned query.
$query_array['select'] = "SELECT contacts.id, contacts.first_name, contacts.last_name, contacts.title, contacts.email1, contacts.phone_work, contacts_cases.contact_role as case_role, contacts_cases.id as case_rel_id ";
$query='';
foreach ($query_array as $qstring) {
$query.=' '.$qstring;
}
$temp = array('id', 'first_name', 'last_name', 'title', 'email1', 'phone_work', 'case_role', 'case_rel_id');
return $this->build_related_list2($query, BeanFactory::getBean('Contacts'), $temp);
}
function get_list_view_data()
{
global $current_language;
$app_list_strings = return_app_list_strings_language($current_language);
$temp_array = $this->get_list_view_array();
$temp_array['NAME'] = (($this->name == "") ? "<em>blank</em>" : $this->name);
$temp_array['PRIORITY'] = empty($this->priority)? "" : (!isset($app_list_strings[$this->field_name_map['priority']['options']][$this->priority]) ? $this->priority : $app_list_strings[$this->field_name_map['priority']['options']][$this->priority]);
$temp_array['STATUS'] = empty($this->status)? "" : (!isset($app_list_strings[$this->field_name_map['status']['options']][$this->status]) ? $this->status : $app_list_strings[$this->field_name_map['status']['options']][$this->status]);
$temp_array['ENCODED_NAME'] = $this->name;
$temp_array['CASE_NUMBER'] = $this->case_number;
$temp_array['SET_COMPLETE'] = "<a href='index.php?return_module=Home&return_action=index&action=EditView&module=Cases&record=$this->id&status=Closed'>".SugarThemeRegistry::current()->getImage("close_inline", "title=".translate('LBL_LIST_CLOSE', 'Cases')." border='0'", null, null, '.gif', translate('LBL_LIST_CLOSE', 'Cases'))."</a>";
$temp_array['CASE_NUMBER'] = format_number_display($this->case_number, $this->system_id);
return $temp_array;
}
/**
builds a generic search based on the query string using or
do not include any $this-> because this is called on without having the class instantiated
*/
function build_generic_where_clause($the_query_string)
{
$where_clauses = array();
$the_query_string = $this->db->quote($the_query_string);
array_push($where_clauses, "cases.name like '$the_query_string%'");
array_push($where_clauses, "accounts.name like '$the_query_string%'");
if (is_numeric($the_query_string)) {
array_push($where_clauses, "cases.case_number like '$the_query_string%'");
}
$the_where = "";
foreach ($where_clauses as $clause) {
if ($the_where != "") {
$the_where .= " or ";
}
$the_where .= $clause;
}
if ($the_where != "") {
$the_where = "(".$the_where.")";
}
return $the_where;
}
function set_notification_body($xtpl, $case)
{
global $app_list_strings;
$xtpl->assign("CASE_SUBJECT", $case->name);
$xtpl->assign(
"CASE_PRIORITY",
(isset($case->priority) ? $app_list_strings['case_priority_dom'][$case->priority]:""));
$xtpl->assign("CASE_STATUS", (isset($case->status) ? $app_list_strings['case_status_dom'][$case->status]:""));
$xtpl->assign("CASE_DESCRIPTION", $case->description);
return $xtpl;
}
function bean_implements($interface)
{
switch ($interface) {
case 'ACL':
return true;
}
return false;
}
function save($check_notify = false)
{
if (!isset($this->system_id) || empty($this->system_id)) {
$admin = Administration::getSettings();
$system_id = $admin->settings['system_system_id'];
if (!isset($system_id)) {
$system_id = 1;
}
$this->system_id = $system_id;
}
return parent::save($check_notify);
}
/**
* retrieves the Subject line macro for InboundEmail parsing
* @return string
*/
function getEmailSubjectMacro()
{
global $sugar_config;
return (isset($sugar_config['inbound_email_case_subject_macro']) && !empty($sugar_config['inbound_email_case_subject_macro'])) ?
$sugar_config['inbound_email_case_subject_macro'] : $this->emailSubjectMacro;
}
function getAccount($case_id)
{
if (empty($case_id)) {
return array();
}
$ret_array = array();
$query = "SELECT acc.id, acc.name from accounts acc, cases where acc.id = cases.account_id and cases.id = '" . $case_id . "' and cases.deleted=0 and acc.deleted=0";
$result = $this->db->query($query, true, " Error filling in additional detail fields: ");
// Get the id and the name.
$row = $this->db->fetchByAssoc($result);
if ($row != null) {
$ret_array['account_name'] = stripslashes($row['name']);
$ret_array['account_id'] = $row['id'];
} else {
$ret_array['account_name'] = '';
$ret_array['account_id'] = '';
}
return $ret_array;
}
}
Hi Ash,
This looks like a syntax error in your custom file.
Please make sure you use two single quotes ' ' below instead of just a one double quote ".
$this->filename = ''; //denotes empty string (two single quotes)
$this->file_mime_type = "; //same as above
$this->file = "; //same as above
Also use php -l custom/modules/Cases/Case.php to further resolve syntax errors if any.
Regards.
Hats
Once again i have clicked on repair then i got this error
Fatal error: Cannot redeclare class aCase in C:\xampp\htdocs\scrm\custom\modules\Cases\Case.php on line 357
This is the code in Case.php
<?php
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
// aCase is used to store case information.
require_once('include/upload_file.php');
class aCase extends Basic
{
var $field_name_map = array();
// Stored fields
var $id;
var $date_entered;
var $date_modified;
var $modified_user_id;
var $assigned_user_id;
var $team_id;
var $case_number;
var $resolution;
var $description;
var $name;
var $status;
var $priority;
var $created_by;
var $created_by_name;
var $modified_by_name;
// These are related
var $bug_id;
var $account_name;
var $account_id;
var $contact_id;
var $task_id;
var $note_id;
var $meeting_id;
var $call_id;
var $email_id;
var $assigned_user_name;
var $team_name;
var $system_id;
var $table_name = "cases";
var $rel_account_table = "accounts_cases";
var $rel_contact_table = "contacts_cases";
var $module_dir = 'Cases';
var $object_name = "Case";
var $importable = true;
/** "%1" is the case_number, for emails
* leave the %1 in if you customize this
* YOU MUST LEAVE THE BRACKETS AS WELL*/
var $emailSubjectMacro = '[CASE:%1]';
// This is used to retrieve related fields from form posts.
var $additional_column_fields = array(
'bug_id',
'assigned_user_name',
'assigned_user_id',
'contact_id',
'task_id',
'note_id',
'meeting_id',
'call_id',
'email_id'
);
var $relationship_fields = array(
'account_id'=>'accounts',
'bug_id' => 'bugs',
'task_id'=>'tasks',
'note_id'=>'notes',
'meeting_id'=>'meetings',
'call_id'=>'calls',
'email_id'=>'emails',
);
public function __construct()
{
parent::__construct();
global $sugar_config;
if (empty($sugar_config['require_accounts'])) {
unset($this->required_fields['account_name']);
}
$this->setupCustomFields('Cases');
foreach ($this->field_defs as $name => $field) {
$this->field_name_map[$name] = $field;
}
}
var $new_schema = true;
function get_summary_text()
{
return "$this->name";
}
function listviewACLHelper()
{
$array_assign = parent::listviewACLHelper();
$is_owner = false;
if (!empty($this->account_id)) {
if (!empty($this->account_id_owner)) {
global $current_user;
$is_owner = $current_user->id == $this->account_id_owner;
}
}
if (!ACLController::moduleSupportsACL('Accounts') ||
ACLController::checkAccess('Accounts', 'view', $is_owner)
) {
$array_assign['ACCOUNT'] = 'a';
} else {
$array_assign['ACCOUNT'] = 'span';
}
return $array_assign;
}
/**
* This function is a good location to save changes that have been made to a relationship.
* This should be overridden in subclasses that have something to save.
*
* @param boolean $is_update true if this save is an update.
* @param array $exclude a way to exclude relationships
*
* @see SugarBean::save_relationship_changes()
*/
public function save_relationship_changes($is_update, $exclude = array())
{
parent::save_relationship_changes($is_update);
if (!empty($this->contact_id)) {
$this->set_case_contact_relationship($this->contact_id);
}
}
function set_case_contact_relationship($contact_id)
{
global $app_list_strings;
$default = $app_list_strings['case_relationship_type_default_key'];
$this->load_relationship('contacts');
$this->contacts->add($contact_id, array('contact_role'=>$default));
}
function fill_in_additional_detail_fields()
{
parent::fill_in_additional_detail_fields();
if (!empty($this->id)) {
$account_info = $this->getAccount($this->id);
if (!empty($account_info)) {
$this->account_name = $account_info['account_name'];
$this->account_id = $account_info['account_id'];
}
}
}
function deleteAttachment($isduplicate="false"){
if($this->ACLAccess('edit')){
if($isduplicate=="true"){
return true;
}
$removeFile = "upload://{$this->id}";
}
if(SugarAutoloader::fileExists($removeFile)) {
if(!UploadFile::unlink($removeFile)) {
$GLOBALS['log']->error("*** Could not unlink() file: [ {$removeFile} ]");
}else{
$this->filename = '';
$this->file_mime_type = '';
$this->file = '';
$this->save();
return true;
}
}else{
$this->filename = '';
$this->file_mime_type = '';
$this->file = '';
$this->save();
return true;
}
return false;
}
/**
* Returns a list of the associated contacts
*/
function get_contacts()
{
$this->load_relationship('contacts');
$query_array=$this->contacts->getQuery(true);
// update the select clause in the returned query.
$query_array['select'] = "SELECT contacts.id, contacts.first_name, contacts.last_name, contacts.title, contacts.email1, contacts.phone_work, contacts_cases.contact_role as case_role, contacts_cases.id as case_rel_id ";
$query='';
foreach ($query_array as $qstring) {
$query.=' '.$qstring;
}
$temp = array('id', 'first_name', 'last_name', 'title', 'email1', 'phone_work', 'case_role', 'case_rel_id');
return $this->build_related_list2($query, BeanFactory::getBean('Contacts'), $temp);
}
function get_list_view_data()
{
global $current_language;
$app_list_strings = return_app_list_strings_language($current_language);
$temp_array = $this->get_list_view_array();
$temp_array['NAME'] = (($this->name == "") ? "<em>blank</em>" : $this->name);
$temp_array['PRIORITY'] = empty($this->priority)? "" : (!isset($app_list_strings[$this->field_name_map['priority']['options']][$this->priority]) ? $this->priority : $app_list_strings[$this->field_name_map['priority']['options']][$this->priority]);
$temp_array['STATUS'] = empty($this->status)? "" : (!isset($app_list_strings[$this->field_name_map['status']['options']][$this->status]) ? $this->status : $app_list_strings[$this->field_name_map['status']['options']][$this->status]);
$temp_array['ENCODED_NAME'] = $this->name;
$temp_array['CASE_NUMBER'] = $this->case_number;
$temp_array['SET_COMPLETE'] = "<a href='index.php?return_module=Home&return_action=index&action=EditView&module=Cases&record=$this->id&status=Closed'>".SugarThemeRegistry::current()->getImage("close_inline", "title=".translate('LBL_LIST_CLOSE', 'Cases')." border='0'", null, null, '.gif', translate('LBL_LIST_CLOSE', 'Cases'))."</a>";
$temp_array['CASE_NUMBER'] = format_number_display($this->case_number, $this->system_id);
return $temp_array;
}
/**
builds a generic search based on the query string using or
do not include any $this-> because this is called on without having the class instantiated
*/
function build_generic_where_clause($the_query_string)
{
$where_clauses = array();
$the_query_string = $this->db->quote($the_query_string);
array_push($where_clauses, "cases.name like '$the_query_string%'");
array_push($where_clauses, "accounts.name like '$the_query_string%'");
if (is_numeric($the_query_string)) {
array_push($where_clauses, "cases.case_number like '$the_query_string%'");
}
$the_where = "";
foreach ($where_clauses as $clause) {
if ($the_where != "") {
$the_where .= " or ";
}
$the_where .= $clause;
}
if ($the_where != "") {
$the_where = "(".$the_where.")";
}
return $the_where;
}
function set_notification_body($xtpl, $case)
{
global $app_list_strings;
$xtpl->assign("CASE_SUBJECT", $case->name);
$xtpl->assign(
"CASE_PRIORITY",
(isset($case->priority) ? $app_list_strings['case_priority_dom'][$case->priority]:""));
$xtpl->assign("CASE_STATUS", (isset($case->status) ? $app_list_strings['case_status_dom'][$case->status]:""));
$xtpl->assign("CASE_DESCRIPTION", $case->description);
return $xtpl;
}
function bean_implements($interface)
{
switch ($interface) {
case 'ACL':
return true;
}
return false;
}
function save($check_notify = false)
{
if (!isset($this->system_id) || empty($this->system_id)) {
$admin = Administration::getSettings();
$system_id = $admin->settings['system_system_id'];
if (!isset($system_id)) {
$system_id = 1;
}
$this->system_id = $system_id;
}
return parent::save($check_notify);
}
/**
* retrieves the Subject line macro for InboundEmail parsing
* @return string
*/
function getEmailSubjectMacro()
{
global $sugar_config;
return (isset($sugar_config['inbound_email_case_subject_macro']) && !empty($sugar_config['inbound_email_case_subject_macro'])) ?
$sugar_config['inbound_email_case_subject_macro'] : $this->emailSubjectMacro;
}
function getAccount($case_id)
{
if (empty($case_id)) {
return array();
}
$ret_array = array();
$query = "SELECT acc.id, acc.name from accounts acc, cases where acc.id = cases.account_id and cases.id = '" . $case_id . "' and cases.deleted=0 and acc.deleted=0";
$result = $this->db->query($query, true, " Error filling in additional detail fields: ");
// Get the id and the name.
$row = $this->db->fetchByAssoc($result);
if ($row != null) {
$ret_array['account_name'] = stripslashes($row['name']);
$ret_array['account_id'] = $row['id'];
} else {
$ret_array['account_name'] = '';
$ret_array['account_id'] = '';
}
return $ret_array;
}
}
Hi Ash,
If you just need a piece of code to delete the attachment, just copy-paste the below code in custom/modules/Cases/Case.php
<?php
/**
* Overridden standard Case bean to copy deleteAttachment method from Note bean
* This enables unlinking of attachment
*/
require_once("modules/Cases/Case.php");
class CustomCase extends aCase
{
public function __construct()
{
parent::__construct();
}
//copy delete attachment function from Note bean, to handle attachment unlink
function deleteAttachment($isduplicate = "false")
{
if ($this->ACLAccess('edit')) {
if ($isduplicate=="true") {
return true;
}
$removeFile = "upload://{$this->id}";
}
if (file_exists($removeFile)) {
if (!unlink($removeFile)) {
$GLOBALS['log']->error("*** Could not unlink() file: [ {$removeFile} ]");
} else {
$this->filename = '';
$this->file_mime_type = '';
$this->file = '';
$this->save();
return true;
}
} else {
$this->filename = '';
$this->file_mime_type = '';
$this->file = '';
$this->save();
return true;
}
return false;
}
}
As you have created a custom bean file, you need to update the bean registry to register your custom bean file.
You can copy-paste following contents to custom/Extension/application/Ext/Include/custom_case_bean_registry.php
<?php
/**
* Custom case bean registry for deleteAttachment override
*/
$beanList['Cases'] = 'CustomCase';
$beanFiles['CustomCase'] = 'custom/modules/Cases/Case.php';
Once you are done, run quick repair and rebuild.
Let us know if this helps.
Regards.
Hats
you're awesome man . It worked Thanks