I've created a new flexible workflow scenario and added some pre-conditions. One of the condition has a single parameter, with a data-element that has a domain with fixed values (YES and NO).
The issue is, in the Fiori app "Manage Workflows", when I use this pre-condition, the value field appears as a free-text entry field, and not as a dropdown with the domain values.
If I change the condition parameter to XFELD, though, I can see the same condition in the app appears as a dropdown with Yes and No options. Due to business requirements, I don't want to use the XFELD, though.
Any ideas how can I get the dropdown for my domain with fixed values?
PS: I've also tried attaching a CDS view VH (view on table dd07l) to the condition parameter. But still the field appears as a free text field.
#AbapCatalog.sqlViewName: 'ZMM_WFL_DEC'
#AbapCatalog.compiler.compareFilter: true
#AbapCatalog.preserveKey: true
#Search.searchable: true
#ObjectModel.usageType.sizeCategory: #S
#ObjectModel.dataCategory:#VALUE_HELP
#AccessControl.authorizationCheck: #NOT_REQUIRED
#EndUserText.label: 'Yes No Domain Fixed Values'
#OData.publish: true
#ObjectModel.createEnabled: true
define view Z_MMPURDecisionVH
as select from dd07l
{
#UI.hidden
key domname as DomainName,
#UI.hidden
key as4local as Status,
#Search.defaultSearchElement: true
#Search.fuzzinessThreshold: 0.8
key domvalue_l as Low
}
where
domname = 'Z_MM_DO_YESNO' --Domain name
and as4local = 'A' --Active
You should define the xsd_type in ct_parameter of your condition as boolean:
ls_parameter-id = 1.
ls_parameter-name = '*Your_name*'.
ls_parameter-xsd_type = if_swf_flex_ifs_condition_def=>cs_xstype-boolean.
ls_parameter-mandatory = abap_false.
append ls_parameter to ct_parameter.
Related
I am trying to achieve flattening a table into an array (or structure). My implementation is in SAP ABAP; however, I believe the question is code agnostic. I am wondering if there is an algorithm I'm not aware of or simple solution for what I'm trying to achieve. I will accept any language or pseudocode as an acceptable answer.
I am selecting from a "User Restrictions" (i.e., lt_restrictions) table stored on a database, e.g.:
This is needed for an SAP BSP MVC web app. When the app loads, I am doing user authorization checks to populate a "User Roles" (i.e., mt_user_roles) local table/array (i.e., attribute on an MVC model class).
The authorization checks involve routine ABAP -- using IF statements to conditionally populate the "User Roles" table, e.g.:
AUTHORITY-CHECK OBJECT 'PROGRAM_MANAGER_AUTH' ID 'xxx' FIELD 'yyy'.
IF ( sy-subrc = 0 ).
APPEND VALUE #( low = 'program_manager' ) TO me->mt_user_roles.
ENDIF.
If the user has both e.g., program manager AND entry user authorizations, this "User Roles" table/array would look like this:
With the two tables above, if the user has program manager and entry user roles, the only restriction is convert; therefore, I need to populate a "Restriction List" (i.e., ms_restrictions) like the following:
Otherwise, if the user has e.g., only the entry user role:
...
...there are 2 restrictions (release AND convert), so I would need to populate a "Restriction List" (i.e., ms_restrictions) like this:
I feel like there is a standard algorithm I could use or perhaps this could be done with SQL in a SELECT statement with my database table WHERE restriction = NULL (e.g., WHERE save = ' ') or using a SELECT ... WHERE x IN clause, perhaps, if the "Restrictions List" was a RANGE table?
I should mention, I already have an undesirable, partial solution which involves looping through the database table and having several IF statements for each restriction condition. "Restriction List" is named ms_restrictions, it is a class attribute ABAP STRUCTURE type (for ABAP newbies, this is basically a 1-D sized array):
LOOP AT lt_restrictions INTO DATA(ls_restriction).
LOOP AT mt_user_roles INTO DATA(ls_user_role).
"Check save restriction
IF (
ls_restriction-role = ls_user_role-role AND
ls_user_role = 'save'
).
ms_restrictions-save = 'x'.
ENDIF.
"Check release restriction
IF (
ls_restriction-role = ls_user_role-role AND
ls_user_role = 'release'
).
ms_restrictions-release = 'x'.
ENDIF.
"Check other restrictions
"......
ENDLOOP.
ENDLOOP.
The problem with the solution above is I have to write an IF statement for each restriction. More so, it doesn't take into account whether there are conflicts between 2 or more role restrictions, e.g., program manager has only 1 restriction while entry user has 2. My logic above could be extended to take this into account with -- well -- even more IF statements :-( .. I'm wondering if there's a different approach I can take?
Also, I should mention. The resulting "Restrictions List", i.e., mt_restrictions, is needed in my view for disabling HTML buttons, e.g.:
<button value = 'Save' disabled = '//model/mt_restrictions-save' />
<button value = 'Release' disabled = '//model/mt_restrictions-release' />
<button value = 'Convert' disabled = '//model/mt_restrictions-convert' />
<button ... />
A solution I came up with involves using ABAP <FIELD-SYMBOL>s data-types and an OpenSQL FOR ALL ENTRIES IN SELECT statement addition.
By using <FIELD-SYMBOL>s, you can avoid any hardcoded attribute and/or structure component names. Now, the restriction rules can grow without having to future modify any code.
By using FOR ALL ENTRIES IN, you can sync your Roles table with your Restrictions table. Adding this clause allows you to SELECT from your transparent Role/Restrictions database table INTO a table, only including the roles applicable from the roles found in the AUTH-CHECK (because mt_user_roles populates a new row for each true AUTH-CHECK).
The method is_standard_user( ) is where the AUTH-CHECKs occur. If it equals ABAP_TRUE, then all restrictions are applied -- assuming the ms_restrictions structure components' values all default to ABAP_TRUE.
Dynamically looping through each structure component of ms_restrictions, you can READ the restrictions table for corresponding value. If value equals SPACE, then this means the current row doesn't have a restriction. So mark the structure component value to SPACE (because it may have been marked ABAP_TRUE in a prior iteration) -- this addresses the "conflicting roles issue".
"perform authorization checks
IF ( NOT me->is_standard_user( ) ).
"see if roles found
IF ( lines( me->mt_user_roles ) > 0 ).
"find pertaining restrictions for roles found in auth checks
SELECT
*
FROM
zmm_apr_roles
FOR ALL ENTRIES IN "select only rows applicable to auth-check
#me->mt_user_roles
WHERE
role = #me->mt_user_roles-role
INTO TABLE
#DATA(lt_restrictions).
"dynamically populate restriction list from multi-role restriction table
DATA: lr_descr_struc TYPE REF TO data.
DATA: lo_structdescr TYPE REF TO cl_abap_structdescr.
CREATE DATA lr_descr_struc LIKE ms_restrictions.
lo_structdescr ?= cl_abap_structdescr=>describe_by_data_ref( p_data_ref = lr_descr_struc ).
LOOP AT lo_structdescr->components ASSIGNING FIELD-SYMBOL(<lv_component>).
ASSIGN COMPONENT <lv_component>-name OF STRUCTURE ms_restrictions TO FIELD-SYMBOL(<lv_field>).
IF ( <lv_field> IS ASSIGNED ).
"non-restricted value overwrites restricted value
READ TABLE lt_restrictions WITH KEY (<lv_component>-name) = space TRANSPORTING NO FIELDS.
IF ( sy-subrc = 0 ).
<lv_field> = space.
ENDIF.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
To add a new restriction, all that needs to be done is:
add new roles to zmm_apr_roles and the corresponding data-dictionary components
add new restrictions to corresponding components of ms_restrictions
Hi i am trying to delete a key value from the context for res.partner form view.
I opening the partner form view using controller function and trying to set phone number as default and its working fine. But when i try to create a new customer by clicking on the create button the phone number again auto-filled. In order to avoid this behaviour, in default_get function, i copied the context into another variable, removed the key value from the context using del context['cc_mobile']. And reassigned to self.env.context. But when i try to create a new customer, the deleted key value comes in the context again.
Controller.py
#http.route('/open_customer/<string:val>', type="http",method=['POST','GET'],website=False, auth="public")
def open_case_window(self,**kw):
mobile_no = kw.get('val')
action = request.env.ref('base.action_partner_form').sudo()
mobile_flag = 0
partner = 'res.partner'
partner_model = request.env[partner]
regex = re.match( '^(?:\01|02|03|04|06|07|09)\d*$', mobile_no)
if regex:
mobile_flag = 0
partner_id = partner_model.search([('phone', '=', mobile_no)]).id
else:
mobile_flag = 1
partner_id = partner_model.search([('mobile','=',mobile_no)]).id
if partner_id:
return werkzeug.utils.redirect('/web#id='+str(partner_id)+'&view_type=form&model='+partner)
else:
context = dict(action._context)
if mobile_flag == 0:
context.update({'cc_phone': mobile_no})
else:
context.update({'cc_mobile': mobile_no})
context.pop('lang')
url = werkzeug.utils.redirect('/web?debug=#view_type=form&model='+str(partner)+'&action=%s'%(action.id))
return url
ResPartner.py
#api.model
def default_get(self, fields):
context = self.env.context.copy()
print'default_get context',context
res = super(Partner, self).default_get(fields)
if 'cc_mobile' in context:
res.update({'mobile':context.get('cc_mobile')})
if 'cc_phone' in context:
res.update({'phone':context.get('cc_phone')})
if context.get('cc_mobile'):
del context['cc_mobile']
if context.get('cc_phone'):
del context['cc_phone']
self.env.context = context
print'self.env.context after',self.env.context
action = self.env.ref('base.action_partner_form').sudo()
action.env.context = self.env.context
return res
You cannot remove a key of action context from python side, because it's in the client side. when ever you call the server like search in many2one field, create a record in fly you will see this context comeback again every time (The way Odoo work).
What you need is something that will be used for one time, I think you need some kind of persistence for example:
dummy model that contains user_id, model_name, value, active fields so in the controller you create a record for default value for that specific user.
get that value by overriding default_get by searching with user_id and model_name field and hide that value or delete it.
this way when yo hit create button or create contact in fly when you search for the value it will be gone so it will not be used a second time.
This a simple Idea and easy to implement, you need to handle some cases to prevent user from saving two default value if some interruption happens should not be hard.
Edit
After second thought to prevent any error when you create a record just pass it's ID in the context with a special key, then use That Id to retrieve it, use it then delete it. easier, safer and no need for search.
I have a custom field being added on user story (HierarchicalRequirement) level.
The WSAPI documentation shows the following details for the field:
c_CustomFieldName
Required false
Type string
Max Length 32,768
Sortable true
Explicit Fetch false
Query Expression Operators contains, !contains, =, !=
When trying to create a report using Custom List to identify user stories where this field is empty, I add (c_CustomFieldName = "") to the query.
And yet, the result shows rows where this field is not empty.
How can that be?
I tried querying on null, but it didn't work.
thx in advance
What you're doing should work- are you getting errors, or just incorrect data? It almost seems like it's ignoring your query altogether.
I tried to repro both with the custom list app and against wsapi directly and the following all worked as expected:
(c_CustomText = "") //empty
(c_CustomText = null) //empty
(c_CustomText != "") //non-empty
(c_CustomText != null) //non-empty
It's possible you're running into some weird data-specific edge case in your data. It may be worth following up with support.
I wanna a user to create a record but later dun give it the right to change the value of that field. should I do it By overriding create and write methods? is it possible to write such code:
field1: fields.float(string='Field',write=['base.GROUP_ID']),
This may work create a status field this field is a compute field when it's true the field1 will be read only. Because i'm on my phone i'm not going to writr the hole code just try to understand the idea
status = field.Boolean(compute='compute_status')
def compute_status(self):
for rec in self:
# first check of the use belong to the group that have full acces
if self.env.user.has_group('group_id') :
rec.status = False
# then check if the record is saved in databse
# unsaved records There id is instance of NewId it's a dummy class used for this
elif instanceOf(NewId ,rec.id) :
rec.status = False # here all users can fill the field when the record is not created yet but cannot edit
else :
rec.status = True # if record is saved and user is not in group_id make field readonly or invisible as you want
Now create your field and use status property to make it readonly when status field is True .
As you can see my answer is algorithme more than a code sorry for sysntax errors
I think the better way to do this is to create a group to which the user will belong, then set in the ir.model.access a rule, with the rights you want, for that particular group.
Ask if you need more help.
EDIT
You can define a view, that inherit from the original one, but is accessible only for the user group, like:
<field name="groups_id" eval="[(6, 0, [ref(' < your group > ')])]"/>
and there you redefine the field making it readonly. That's it.
I had a User model, with attributes email, name ...
I wanted to add a column has_agreed with a default value true. So I added that migration and ran it, it shows properly in the database. Now when I fetch the value, #user.has_agreed, it does not return me any value. I have written has_agreed in the attribute accessible (Rails 3.2).
If I manually change the contents of the database by an update command for this particular user to change has_agreed value to false for user with id 1 and then run the same call, #user.has_agreed, it returns false.
I have historical data and I want to add this default column and can not and do not intend to manually update this column through database. How to get the value?
Also, the issue is with only the old users in the user table. For the new users it works fine.
in user.rb
class User
def has_agreed
# use this line code. if has_agreed not equal false
# read_attribute(:has_agreed) || default_velue
if read_attribute(:has_agreed).blank?
## default value
true
else
read_attribute(:has_agreed)
end
end
end