Tuesday, November 15, 2016

Did you know? Apps aliases must be unique cross workspace

... and Oracle isn't checking it for you!


Hi,

this is just a quick note. Seems logical, but YOU have to take care of it!

Recently I uploaded an APEX export file from an app that my colleague had created.
I just wanted to check something he had done, so I uploaded the application in my own workspace. That's a workspace I use to quickly check something or do some research on.
It is however on the same database that my colleague is using to develop this particular application. And his customer is actually looking at that environment as well during the development phase.

So I uploaded the the export file and installed the app, accepting all the defaults there are when you import and install an APEX app.
But what I didn't know, is that APEX is NOT changing the application alias. Something that is done when you import an app that got exported from the same workspace. I believe it adds the new application ID to the alias.

But since this app came from a different workspace, it nicely installed it with the existing alias, causing the original app to fail.

So I just wanted you to know ... I will never forget this. And you may learn from my mista ... well ... from my experience! ;-)

Happy to share!

Wednesday, April 6, 2016

Apex: Save interactive report as default when integrated with EBS

This is something I shared quite some time ago (back then it was APEX 4.x, but it's still valid) on another forum. But I got the question back lately. So, here I am back with the same message ....


An integrated Apex App with Oracle E-Business Suite (EBS) has an unfortunate side effect concerning Interactive Reports.

Some of the settings of such a report is easiest done when running that report as a developer and then save it as Default and Primary Report Setting. So everybody who runs the report gets to see it the way you - as developer - has saved it.

When you execute the Apex app from within the EBS, the user you're using to connect to Apex is inherrited from EBS and as such not an Apex Developer user. Consequence: you are not allowed to save your IR as Default setting!

The trick around this to logon to Apex builder (as developer obviously) and to the EBS with the same browser session.  Then launch your app via EBS.  So the app opens in the same browser as the one used by your Apex builder.

In your app you have now the oportunity to use the edit-bar (at the bottum: "Home" / "Application" / "Edit page" / .....) and ... most of all, you can in this session save your reports as default (and primary) setting.  Which is the solution of the problem.

Happy to share ...

Tuesday, February 23, 2016

Duplicate page submits cause double database entries

No more double entries, please


In many applications the result of a page submit is the creation of one or more lines in some database table(s).
When these processes become heavy and have to take a lot of business rules into account and that perhaps in combination with sometimes not optimal network trafic, it may happen that the user doesn't see that APEX is processing his stuff.
As a result he or she may become impatiant and start hitting that Save button over and over again ...

When this results in multiple occurance of the record in the database, this creates data inconsistency. Something that every developer is - quite rightfully - scared as hell for.

There are some ways to prevent this behaviour from happening.

This blogpost is about preventing those double entries. But while doing my research and in fact the winning tip for the solution was coming from my good friend and APEX mentor Dimitri, I found a very nice extra. 
Did you, just like me, wonder how the APEX Builder has this spinning wheel showing up when saving your changes? And could you, just like me, not figure out how that was done? Well ... just read on!

So here's my business case.
A reasonably complex APEX page has a couple of buttons:
  1. Cancel - needs no explanation
  2. Save - simply writes the entered date to several tables in the database
  3. Finalize - does the same things as "Save", but also starts an approval workflow process

In our case, this Finalize was the issue.
Kicking off that workflow requires some business logic, some validations, well, it's a process that wasn't done in milliseconds.
Nothing was done on the APEX page to prevent the page from submitting multiple times. And nothing was done to show the end user that a process was running.
The only thing: when the process was done, then a message was shown, something like "Well done, your request has been sent to your manager".

The first week after go live of the system, we noticed that our end users were much more impatient then our test users. Because they didn't immediately saw the result of the 'press on the button', they started hitting that button multiple times. And so submitting the page multiple times. And so creating the same record multiple times.

So let me show you in this very much simplified sample what was the first setup of the APEX application.

The old way

Nothing was done to prevent double entries at all.
Base table used is hr_employee.  And it contains some very basic personnel information.

Only 1 record in there before the exercise:


On this table a form with report was created.



So I start hitting this Apply Changes button like crazy and it's almost impossible to mimic the customer's case with this simplified example.
But believe me, it happened and let say Mr. McEnroe is created twice in the db.




An important setting to keep in mind in this example is on page level


This setting can allow or prevent the page to be resubmitted multiple times. This feature was called into place to prevent a page to be resubmitted e.g. after a page reload in the browser. Or when hitting the back and forward button of your browser.
So ... there is our first clue!

The button (Save and Apply Changes) are both performing a Page Submit.


One step up and prevent page from being reposted

So I could redo all the steps as described above, with this option set to "No - Prevent this page from being re-posted". But I'm not gonna, because you will not see the difference, except for this one single setting:

In most situations this setting will save you. Although, if you remember the customer case, this setting was already set to prevent the re-posting.
So our example wasn't about being reposted or not. It really was due to multiple submissions. It was like the process was launched a second time, before the first time had come to an end.
There are other reasons why we could assume this, because at some point in the process it was checked if a request could be approved and then some status was changed so the same person could never approve twice the same request.  Because this little piece of functionality was in there and it had never occurred during test cycles, we were pretty confident that we had built a safe system.

Until ... one week after go live the customer came back to us and said: "multiple occurrences of the same record exist, created within less than a second from one and another. Please help!!!"
And then, the main test user had a brilliant idea. She sat down behind her computer, opened the specific page, entered some data and pointed the button and started clicking it like mad.
And there it was ... not two or three, but at least nine or ten records were saved to the db. 

So we needed another solution. And when I ran out of ideas, I called a help line.

Disable the button after having pressed it

The solution is as easy as it is simple. Prevent the the button from being pressed more then once.
In example one and two, the process was launched upon page submit. The button basically submitting the page.

Compared to both examples above, the change is with the button definition. No longer use the Page Submit, but set its behaviour to Defined by Dynamic Action.


Note: in this example we need the Database Action. In many cases you will not need that, but you will launch your actions via a page process.

 Now create the dynamic action:



First DA True Action:
Disable the button, making sure it is NOT fired on Page Load (by default it will fire on Page Load).

Finally add a second DA True Action:
To stick to the original behaviour, it's quite simple: just perform a Page Submit and set the Request to the Button name (Create). This is important, otherwise the defined page process that was previously directly linked to the button, will not be fired.

For the Page Submit obviously the default is set that the action should not fire on Page Load.
And look what came with this solution for free!




Yup ... the spinning wheel. There is that very nice extra that I was talking about in the introduction.
From now on - until further notice - I believe this will be my standard way of building an APEX page that submits something to the DB. 
I will no longer submit the page directly from the button, but will have a dynamic action do this, after I have disabled the button.

Also when you stay on the same page after the process is done, you do not need to enable the button again. Your Page Load will do this for you.


For me this really was an eye opener. For so many years I was used to write as much as possible in page processes that got fired on Page Submit.
I even made a habit out of it to - when possible of course - only write something to the DB after a page submit.
And it never occurred to me to do this in another way than via the button behaviour "Submit Page".

As simple as it may seem and as logic as it in fact is ... I only discovered this recently. I don't know if the APEX Builder is using the same method, but it looks the same. And that's good enough for me ;-)


Happy to share ...



Wednesday, September 30, 2015

Copy Theme Roller settings from one app to another in APEX 5.0.1

Just a note, more for myself than anything else. So I quickly can find it back, because somehow I keep on forgetting the command and then I'm spending too much time in finding it back.

So this is what you do when you've created a theme roller styling that you like and want to copy to another (or all your other) apps.
What I typically do is created a style in one app. When it's all finished and approved by the customer and I've gathered all signatures  - ;-) - then I run this command in the console of the browser.

Make sure your Theme roller is opened when you open your console of the browser!

> apex.utr.config()




As stated on the prompt, just copy that JSON file and go to the application where you want to import it.
Also there first open Theme Roller and then open the console of your browser.

Simply paste that line and hit enter.

Now your settings are loaded into the Theme Roller of your new app. Use Theme Roller (save as) to save your settings in the new app ...

This is APEX 5.0.1. In APEX 5.0 you have to make a small change to the text and add the "apex." in front when you have pasted it in the new app ...


Happy to share ...


Monday, August 3, 2015

Migrate your apps to Universal Theme in APEX 5

Hi and happy to be back.

Somehow I forgot what blogging was. But constructing a house, making it your home and moving into that new home took quite some time and above all energy. So blogging didn't have my highest prio for the last couple of months.

I know, it's just excuses, but as all that is none of your interest, I'll get on with the work :-)


So, I'm preparing a demo / workshop to show people what, how and why to migrate your apps to the Universal Theme (UT) once you did the technical migration to APEX 5.

This is all very well documented by the Oracle APEX Team, fow which many many thanks!
Here's just an overview of what I needed when doing my research. I'll build up the blog post along with my prep.



Migrating to Universal Theme

What is this UT?

So what is this UT and what's all the fuss about it?
Well, these insights from my point of view, not a commercial talk, nor a high-specialist talk. But an every day APEX developer and Oracle specialist.
I believe that my profile of developer is exactly why they have developed the UT to begin with.
I was trained by Oracle in the mid-nineties. This means PL/SQL, Oracle forms, PL/SQL, Oracle Reports, PL/SQL, Designer, PL/SQL and also some PL/SQL.

I have gradually picked up some HTML knowledge. Learned to deal with XML and more recently also JSON file formats.
I've upgraded my knowledge via self-study on CSS, Javascripting and I'm following some blogs on web-design in general. I try to keep up with the latest, which is not always easy. From the web-design/development point of view: I'm an old guy.

So UT for me exactly takes away those deep technical requirements that I'm not specialised in.
Still I urge you to have some knowledge of the web development skills mentioned above. But UT will help  you a lot!

And there is one more thing I like so much about the UT: 
as developer we can come up with great ideas of what an app can/should do. We're also capable of actually building just that. But what about the design, the user interface? It's often not our strongest skill. I know it's not mine. On top of that: I'm color blind. I literaly see things differently than other people.
Now with the UT, they can build the app and don't bother too much on the color schemes. Because it can be changed once you're done developing. Or during development. There even is a Theme Roller which allows you to change colors of the objects and it picks colors that fit together. More later, but ... honestly: WAW !

Other than all that, there are a number of reasons why you should migrate to UT. Or at least try to, because there are also some down sides. But all this is well explained in the Oracle documentation.

 So my first link: The Oracle Migration Guide.

How to decide to migrate or not?

Yeah, well, good question.
You may have good reasons to oppose against UT. Perhaps you have invested a lot in your own custom theme. With lots of nice looking stuff in there that works just as you want it to.
Although perhaps UT has those customizations built-in standard, it will take an effort to match and align them. Not even having spoken about the testing efforts after migration.

UT follows the latest stuff in web design. Certainly concerning navigation it is quite a change to the old style of navigation. But what if you actually like that? Perhaps you or your users are not so keen on change?

And another important - if not the most important - reason why not to migrate: you have invested already a lot in development of the app(s) in the first place. Now you have to invest in those same apps.

Bottom line: think about these things upfront and discuss them fairly with your boss or customer.
We as developer probably all wouldn't like anything more than to migrate. Don't forget it comes with a price tag!


Backup there ... slowly, one step at the time

Of course, first backup the app you want to migrate. And also of course, I'm assuming that the technical upgrade to APEX 5 has been successfully done.
One reason to take a backup is the obvious one: it's a backup.

But I hadn't thought of a second one myself until it was pointed out to me: once you have migrated your app to the new UT, it's a good idea to import the old one (with a new APPLICATION ID) so you can run both versions at the same time. And do all your tests.
If there is something you don't like, you can start off again from the original version and migrate all over again.
Probably a good idea to run each version in another browser.

Now let's take it step by step

Basically all I'm doing here is following the steps in Oracle Migration Guide!
So it seams a bit over the top to retype those steps here. and I don't want you to think that I came up with all those steps by myself ;-)
So open that migration guide in a different window or tab and leave it open!

Therefore again: The Oracle Migration Guide.
But there are some things you need to know about your old app before you migrate.
UT is far more grid orientated then the old themes. That is, if you had already a GRID theme to begin with!
So take some time to investigate on this.
Another very important one is the TAB-levels used in your old theme. UT doesn't use tabs anymore (thank you very much!) and it the Wizard is not capable of migrating apps that have multi-level tabs.
If this is your case, then first go and adapt the original theme to one-level tabs!

Follow Oracle's guidelines on the migration when switching from old to new.

Match template classes?

The migration guide tells you to switch this option to "No", without explaining why.
So what do I do? Yup, I left it to its default ("Yes").
And it all worked out fine. I was lucky? No, I wasn't ... I just had a very simple app to start off with.

However there must be a reason why they say to switch it to "No".
And there is. It's all the next step: the mapping of the classes.
APEX will try to help you with this mapping. But when this option was set to "Yes", it will only offer templates that are from the same class as the original ones. This will often NOT be the case and you will be left with quite some frustrations when migrating the more complex apps!
So keep control and believe Oracle there ... switch it to "No"!

Map your templates tot the UT templates

Although this is just a small step as described in the guide, take your time here. You even may want to try different versions of migrations in order to find the right settings.
It will save you a lot of time if you do the correct mapping here, rather then just picking one and you're left with a whole lot of individual changes on every page of your app to correct the situation.
Here once more the backup of the original app may come in handy!

Because this is such an important step, I'm taking some more time on it:

So here is a very simple example of an app created with the Blue responsive theme 25.
UT was not created yet in this application before I started.

And this is how the working app looks like in APEX 5 without having migrated it to UT:

So I create the UT in the application.
And I start the Switch wizard.

First attempt with the Match Template Classes set to "Yes" (against Oracle's advice).


Mapping:



Note the mapping options for Standard Region:

 
This actually is a reminder for you that you have the mapping option set to "Yes". Because see what happens if you go back one step and set it to "No".

You can actually just go back here with the "<" button.


Note the mapping options for Standard Region now:




Already here you should be convinced to set that parameter to "No". Actually, it beats me why the "Yes" exists in the first place and even more why that is set as default. But that's probably just me ;-)

And now comes the nicest part of this step. the Universal Theme Migration Helper.
Today (3rd of August 2015) it's up to version 1.1 supporting themes 21, 22, 23, 24, 25 and 26.
If your custom theme is based on one of these, then certainly pay attention to this section of the migration guide.
I have now added the Bookmarklet to my bookmarks (in my case the browser is Chrome):



For the more complex apps, this will make a huge difference in the mapping proposed by APEX. In my case there's not a lot of difference as my app is a very basic example.
But adding this Bookmarklet is an easy thing to do and you need to this only once. Well, for each browser you're using in case you use multiple browsers.

And this is what it looks like in APEX 5 in Universal Theme:



My conclusion

It's all relatively easy to do. But do your homework first.
Know where you start from.
And thoroughly test your migrated apps on look and feel AND on functionality.

Mind you, now you've only done a migration. You should investigate also if you can replace some custom stuff with standard APEX 5 + UT stuff. A lot of things are in there that weren't in the old themes (or APEX version). You've just taking the effort to migrate, now is the good time to look into the app to see if you can replace/remove some custom work. I strongly believe that it's way better to stick as much as possible to the standards of APEX!

And my advice: try to migrate. It will pay off in the end.
If you have many applications - may be even linked to one another - start with one and see if it still works all together.
And then take it one by one. Keeping in mind that the user interface changes. So apps that belong together, probably need to have the same UI feeling.
Grouping your apps is never a bad idea.


Theme Roller

I promised some more on the Theme Roller.
Well, following screenshots speak for themselves. Id didn't write one single line of code. I didn't know any of the names of the colors used. I just turned the wheel ... very easy to go and find (or create) your company color scheme. And the different styles can be saved and re-applied to other apps.

Before





After(s)




I'm not pretending this color combination is a good idea! Just wanted to point out how easy it is to change it ... :-p

 And if you're still not convinced, have a look here:







Thanks for sticking with me up to here :-)
and happy to share ...

Tuesday, February 17, 2015

A nice query to have when dealing with DATES in Oracle


Dates in Oracle. 

It's not always easy, whereas in fact it should all be plain and simple.
Only too often I've had problems with dates myself in the past. The other day I was asked by someone to have a look at his code and while debugging the source of the problem was ... yup, a wrongly interpretted date format.

So I thought digging up a query I made once when I gave a beginners training for SQL. This is a query that might put you in the right direction ... I hope it's useful for you!

The ':' is used for you to enter a date in the given format. You may need to replace this ':' depending on which query tool you're using.

select to_date( ':ddmmyyyy', 'ddmmyyyy') date_reference
     , to_char( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'day') weekday
     , to_char( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'IW') week_number
     , trunc( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'yyyy') start_year
     , trunc( add_months( to_date( ':ddmmyyyy', 'ddmmyyyy'), 12), 'yyyy') - 1  end_year
     , trunc( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'IW') start_week
     , trunc( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'IW') + 6 end_week
     , trunc( trunc( to_date( ':ddmmyyyy', 'ddmmyyyy'), 'yyyy'), 'IW') start_week_one
  from dual
  ;

Happy to share!

Tuesday, February 10, 2015

Attachments in APEX Application

Uploading Attachments

So often it is not enough to be able to display data and to provide a good UI for data handling.
Every now and then you need to be able to store complete files in your DB.
That can be technical drawings or a paper that has a signature on it.

Whatever reason you have for it, I will show you two options how you can include the attachment functionality in your APEX apps.

Following examples are all built with APEX 4.2.x.
Things change in APEX 5. Roel Hartman blogged about it a couple of months ago.

Include the file in your main table

E.g. you want to support the possibility to attach a file to a screen.  One single file only.
I once had to do this to support a sort of workflow driven process.
In the process of data gathering, at some point to be able to move to the next status, it was required that a specific document was attached.

The page was built using an Automated Row Fetch and Automated Row Processing.
So there I opted to include the file in the dedicated table for that page.

Your table definition

You need to have some columns in your table, of course you can add them via an alter table statement if this requirements comes up during your development process.
Those dedicated columns are:


Column name Data type
DOC_BLOB BLOB
DOC_MIME_TYPE VARCHAR2(100)
DOC_FILE_NAME VARCHAR2(250)
DOC_UPDATE_DATE DATE


In most cases those columns will be NULLS ALLOWED. But that depends on your functional specifications.

Example in the APEX page before the upload



The APEX solution

You will have on your page following page items:


Filebrowser P73_DOC_BLOB





Storage Type: I opted here for the Storage Type "BLOB", because this is the case where the file is stored in the table specified by Automated Row Processing.

MIME Type column: It is in fact not required that this column exists as page item on your page. I did it anyway, but made it hidden.
In this column the mime type of the uploaded column will be stored.

Filename Column: this is where the filename is stored. This can be easily retrieved via SQL to display elsewhere that a file has been attached. Possibly with a download link.

BLOB Last Updated Column: will contain the timestamp as used by browser caching to identify if the file has changed.

Download Link text: this text will be shown once the file is uploaded (see picture below)

Content disposition: (as copied from the APEX help info:) Content Disposition is used by the browser to decide if the downloaded content should be displayed inline within the browser window or if the open dialog should be displayed. Not all content will be displayed inline, it depends on the supported mime types.


This identifies that the file will be uploaded to the column DOC_BLOB of the table specified by the Automated Row Processing.


I added a Read Only condition. Once a file is uploaded, it will be shown in R/O modus. The page has a specific button to delete the file.


Example in the APEX page after the upload




Use a dedicated attachments table

A second method to store attachments is to make use of a dedicated table that stores all files.
you link the file to its specific function with a foreign key link.

This method will be often used when you must be able to add multiple files to a functional area.
You can think of a person-record in an HCM database for which the scanned ID-card must be attached, but also the (paper scanned) CV of that person. 

Example in APEX

As often, there are multiple ways to implement. You can make a separate page (perhaps a modal window) where you can upload as many files as you want.
But in a specific case I was asked that the number of attachments had to be limited to a maximum of 10 files. I opted to stay on the same page and implemented the following:




This comes down to the following region on my page. 
I admit that I would not choose for this implementation for more than 10 attachments. To be honest, I think now that ten is already too much. But the requirement started with 3 files max and I had already built the solution when the customer explained they needed "a small change on the attachment functionality" and they needed up to 10 files ...



The REMARK field is a simple text field on your page. Nothing special.
The ATTACHMENT field needs some explanation.

Filebrowser P27_ATTACHMENT1

This filebrowser needs less specification compared to the one explained above. But following are important:



The storage type now points to the table WWV_FLOW_FILES. This is a table used by APEX to store the files. It is intended as a temporary table and you should after upload move your files to your own table. Moving in our case comes down to copy to the new table and then delete it from the WWV_FLOW_FILES table.

To do so, you will need a separate page process.

Page process to upload the attachment

I had created a page process that fires upon page submit. But of course you can also add a button that triggers a dynamic action and performs the same logic.

How to deal wit WWV_FLOW_FILES

You can access this table by using your page-item (e.g. P27_ATTACHMENT1) that holds your file.
And that you use to copy (insert) the file to your own table:

insert into my_attachments_table
   ( doc_blob
   , doc_mime_type
   , doc_file_name
   )
   select blob_content
        , mime_type
        , :P27_ATTACHMENT1
     from wwv_flow_files
    where name = :P27_ATTACHMENT1;

So that will be the first step in your process.
This must be immediately followed - as per good practise and advised by Oracle - by deleting the file from the WWV_FLOW_FILES table:

delete from wwv_flow_files where name = :P27_ATTACHMENT1;

A smart thing of course to do is to only execute this code if an attachment was added. Do this via a condition (:P27_ATTACHMENT1 must not be null).



Downloading Attachments

I've provided you with 2 options to upload attachments. But of course you must also be able to download them.

As shown in the first option of uploading attachments, when you use the BLOB mechanism of APEX, the download link is automatically created for you. Nice and easy! 

But you can also add a download link in a report. When you have some nice icons uploaded or you have integrated something like Font Awesome, you can even use a nice icon in stead of the "download" text to do this.

But here's a quick example:


The SQL behind it:
select att.attachment_id
     , att.proposal_id
     , att.remark
     , att.doc_file_name
     , substr( att.doc_file_name, instr( att.doc_file_name, '/') + 1) as short_file_name
     , dbms_lob.getlength(att.doc_blob) as doc_blob
     , null as delete_me
  from my_attachments_table att
 where att.proposal_id = :P14_PROPOSAL_ID

Two important columns for us now:
  • delete_me
  • doc_blob

Delete Me
Let me start with the delete option.
I hadn't spoken about it, but you will probably want to allow the end user to remove a file again from the database.
To do this, I've created a (hidden) page item to capture the attachment-id.
This item triggers a dynamic action (on change) that will remove the specified attachment.
And to change that hidden item (and by consequence trigger the dynamic action), I use a link on the column name with in the URL following javascript code:

javascript:$s('P14_DELETE_ATT_ID','#ATTACHMENT_ID#')

This is what the column link looks like:



Do not forget to Display the delete (and download) column as "Display as text":



When you click the link, the javascript will fill the page item :P14_DELETE_ATT_ID with the value captured in #ATTACHMENT_ID#, which is the value of the specified line in your report.

Following mechanism will be triggered:



The PL/SQL to be executed is fairly simple:


(do not forget to submit the page-item)


The refresh will make sure your page is immediately refreshed with the new content (removed file).


Doc Blob
The DOC_BLOB contains your download settings.

This is the somewhat tricky bit. Specify following syntax in the Column definition's Number / Date format of your report query:
DOWNLOAD:MY_ATTACHMENTS_TABLE:DOC_BLOB:ATTACHMENT_ID::::::Attachment:download



The Blob Column Attributes point to your (custom) attachments table:






Happy to share ...