Skip to main content
Question

Portfolios License Archiving Process

  • December 11, 2025
  • 2 replies
  • 55 views

Forum|alt.badge.img+1

We are evaluating the most cost effective way to manage our licenses so are currently defining an archive process based mostly on lack of use.  I’d also like to downgrade a Portfolio-R/W license to a View Only license if I could tell if the user has not made any data updates in the past three months or so.   Does anyone know a way to do this?

We are also considering alternative solutions like report subscriptions to keep licensing costs down and wonder if others have pursued this or any other solutions?

Thanks!

This topic has been closed for replies.

2 replies

Forum|alt.badge.img
  • Silver Active Participant
  • January 6, 2026

FYI: There is a tile called “Users” that shows last login.

I wrote a quick script (attached to tile) that shows last users where last login was > x days. We also check for users where maybe the resource got disabled but the user didn’t. I’ve not done data update checks, but it sounds doable using a custom script. 

We are doing some reporting outside Portfolios using API’s. 


Forum|alt.badge.img
  • February 12, 2026

Licensing can be controlled with Planview’s SOAP API.    You can change this dynamically based on user needs.   

 

Sample Code.

def update_license(df, hostName, PVCert):  # Need a Dataframe with "License","User ID","Name"    wsdl = "https://" + hostName + "/Planview/services/UserService.svc?wsdl"    client = Client(wsdl=wsdl, port_name="BasicHttpBinding_IUserService")    headers = {"Content-type": "text/xml",               "Cookie": PVCert}    client.transport.session.headers.update(headers)    count = 0    for idx, row in df.iterrows():        try:            results = client.service.Update(dtos=dict(UserDto={"UserKey": "key://3/" + str(row.loc["User ID"]),                                                               "RoleKey": "key://2/$Role/" + "923"   ←   You need the license SQL key Number                                                               }),                                            )            if results["Failures"] is None:                logger.info("%s was updated successfully with new license code",row.loc["Name"])                count += 1            else:                logger.info("--------%s failed to be updated with New License Code --------",str(row.loc["Name"]))        except Exception as e:            logger.exception(                "Failed to update %s in Planview (attempted New License Code %s and resource role %s)",                row.loc["Name"],                row.loc["New License Code"],                row.loc["resource_role"]            )    return count